Можно ли написать функции C, которые изменяют структуры типов, определенных в коде Go?
Это продолжение этого вопроса. Я сделал предположение, что это может быть неверно, поэтому я прямо спрашиваю об этом. Поскольку я забыл спросить, действительно ли это возможно, я уже зарегистрировал issue # 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? Конкретная точка этого изложена в связанном выше вопросе; Я хочу, чтобы marshall C-структуры, к которым невозможно получить доступ из кода Go, либо потому, что они используют союзы или битовые поля, либо потому, что их выравнивание делает их несовместимыми с кодом Go.
Ответы
Ответ 1
Насколько я знаю, нет, вы не можете.
Но вы могли бы использовать что-то некрасивое, как https://github.com/OneOfOne/go-nfqueue/blob/master/nfqueue.go#L130, где вы экспортируете функцию Go, которая занимает много указателей и создает вашу структуру Go в перейти.
Ответ 2
Я написал следующий грязный хак, чтобы обойти очевидную неспособность получить доступ к структурам 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.