Можно ли написать функции C, которые изменяют структуры типов, определенных в коде Go?

Это продолжение этого вопроса. Я сделал там предположение, которое может быть неверным, поэтому я прямо спрашиваю об этом. Поскольку я забыл спросить, возможно ли это на самом деле, я уже подал проблему. #8114 об этом.


С помощью cgo можно заставить код Go работать с типами C, например так:

package foo

//#include <sys/stat.h>
import "C"

func fileSizeFromStat(stat *C.struct_stat) int64 {
    return int64(stat.st_size)
}

Возможно ли обратное? т.е. писать функции C, которые работают с типами go? Конкретный момент этого изложен в вопросе, указанном выше; Я хочу сортировать структуры C, к которым нельзя получить доступ из кода Go, либо потому, что они используют объединения или битовые поля, либо потому, что их выравнивание делает их несовместимыми с кодом Go.


person fuz    schedule 29.08.2014    source источник
comment
Зачем вашему маршаловскому коду нужен доступ к типам Go?   -  person rog    schedule 29.08.2014
comment
@rog, потому что он упорядочивает типы C в типы Go.   -  person fuz    schedule 29.08.2014


Ответы (2)


Насколько я знаю, нет, нельзя.

Но вы можете использовать что-то уродливое, например https://github.com/OneOfOne/go-nfqueue/blob/master/nfqueue.go#L130, где вы экспортируете функцию Go, которая принимает много указателей, и создаете структуру Go на ходу.

person OneOfOne    schedule 29.08.2014
comment
Я очень надеялся, что это не будет ответом. Оставьте это открытым еще на некоторое время. - person fuz; 29.08.2014
comment
@FUZxxl, да, я надеюсь, что кто-то другой тоже знает лучше, так делать больно. - person OneOfOne; 29.08.2014

Я написал следующий грязный хак, чтобы обойти очевидную невозможность доступа к структурам Go из C. Хотя этот хак не гарантирует работу, он работает в тех случаях, когда Go и C договариваются о том, как размещать структуры, что оказывается чехол для всех тех случаев, которые меня интересуют.

Для каждой структуры Go, к которой я хочу получить доступ

type JewelTarget struct {
    SensRes [2]byte
    Id      [4]byte
    Baud    int
}

Я создаю соответствующую структуру C, которая имеет поля одинаковой ширины и, надеюсь, такой же макет:

typedef ptrdiff_t GoInt;

struct JewelTarget {
    uint8_t SensRes[2];
    uint8_t Id[4];
    GoInt   Baud;
};

Затем я пишу функции C, которые используют эти структуры C:

extern void
marshallJewelTarget(nfc_target *nt, const struct JewelTarget *jt)
{
    nfc_jewel_info *ji = &nt->nti.nji;

    memcpy(ji->btSensRes, jt->SensRes, sizeof(jt->SensRes));
    memcpy(ji->btId, jt->Id, sizeof(jt->Id));

    nt->nm.nbr = jt->Baud;
    nt->nm.nmt = NMT_JEWEL;
}

и вызывать их так, как если бы аргументы имели соответствующие типы Go:

func (d *JewelTarget) Marshall() uintptr {
    nt := mallocTarget()
    jt := (*C.struct_JewelTarget)(unsafe.Pointer(d))

    C.marshallJewelTarget(nt, jt)

    return uintptr(unsafe.Pointer(nt))
}

Все примеры взяты из моих привязок nfc.

person fuz    schedule 29.08.2014