Как вернуть указатель C из функций Go?

У меня есть вопрос, возможно ли вернуть из Go указатель на функцию C? Например, main.c может быть:

struct open_db_return db_ptr = open_db(db_path);
  GoSlice backet = {"DB", 2, 2};
  GoSlice key = {"CONFIG", 6, 6};
  struct get_value_return val = get_value(db_ptr.r0, backet, key);
  close_db(db_ptr.r0);

Go код следующий:

//export open_db
func open_db(path string) (interface{}, error) {
    db, err := db.Open(path, 0600, nil)
    if err != nil {
        return nil, err
    }
    return db, nil
}

//export close_db
func close_db(db interface{}) {
    ldb := db.(*db.DB)
    ldb.Close()
}

//export get_value
func get_value(db interface{}, backet_name []byte, key_name []byte) ([]byte, error) {
    ldb := db.(*db.DB)
    var value []byte
    fn := func(tx *db.Tx) error {
        value = tx.Bucket(backet_name).Get(key_name)
        return nil
    }
    return value, ldb.View(fn)
}

После cgo команда go build -buildmode=c-archive test.go я получаю заголовочный файл и пытаюсь связать его с моим проектом c командой gcc -g -pthread main.c test.a -o main, все скомпилировано и связано успешно, но во время выполнения я получаю следующую ошибку: panic: runtime error: cgo result has Go pointer Идея состоит в том, чтобы получить указатель на БД в c, выполнить некоторую работу, а когда БД не требуется, закрыть БД.

2 ответа

Как говорит ДжимБ; это, вероятно, не будет работать (это называется unsafe по причине). Даже если вам удастся навести указатель на что-то C, существует большой риск из-за того, что сборщик мусора в Go потенциально освобождает базовые ресурсы, потому что Go не знает об использовании в C

оригинальный ответ

Я думаю, что подпись для open_db должно быть: func open_db(path string) (unsafe.Pointer, error)

И переменная db следует преобразовать в unsafe.Pointer; наивно так return unsafe.Pointer(db), err но я не знаю специфики реализации базы данных в этом случае.

Ваш close_db функция, вероятно, также должна принять unsafe.Pointer вместо interface{}

Смотрите: https://golang.org/cmd/cgo/

Если вы хотите вернуть байтовые данные, вы можете вернуть unsafe.Pointer и размер байтовых данных. Я использую func C.CBytes([]byte), он возвращает unsafe.Pointer

Другие вопросы по тегам