Сложность доступа к вложенному члену C в go - PullRequest
1 голос
/ 19 октября 2019

Отказ от ответственности: я новичок в Go / CGo.

Я работаю с этой структурой C на 64-битной платформе, пытаюсь получить доступ к члену uint32 объединения

typedef enum {
    n = 0,
    ix = 1,
    iy = 3 
} enum_x;

struct smallStruct_s {
     union {
        uint32 a[4];
        uint32 b[8];
        uint32 c[16];
    } u;
} smallStruct_t;

struct bigStruct_s {
   enum_x fa;
   union {
        uint32 member_to_access; <<<<<< This is member that needs to be accessed
        smallStruct_t an;
   } un_t;
} bigStruct_t;

Я сталкиваюсь с трудностями при доступе / мутации member_to_access в Go, если у меня есть доступ к bigStruct_t, к которому можно получить доступ с помощью C.bigStruct_t.

Как я могу передать адрес member_to_access с помощью unsafe.Pointer вфункция, которая принимает void * в C без нарушения каких-либо ограничений памяти.

Машина с прямым порядком байтов

Я пытался использовать буферы byteArray и C, как упомянуто в Golang CGo: преобразование поля объединения вВведите , но не можете понять, почему функция принимает в качестве параметра массив размером 8 байт.

1 Ответ

0 голосов
/ 21 октября 2019

Объединение может быть представлено в виде массива байтов, поэтому это поле весит как размер самого большого элемента ([sizeof_union's_largest_element] байт). Enum может быть представлен как int.

Я предлагаю использовать для этого смещения:

type bigStruct struct {
    instance unsafe.Pointer
}

func (bs *bigStruct) fa() int {
    return int(*(*C.int)(bs.instance))
}

func (bs *bigStruct) memberToAccess() uint32 {
    // C.sizeof_int refers to sizeof(enum_x)
    return uint32(*(*C.uint32_t)(unsafe.Pointer(uintptr(bs.instance) + C.sizeof_int)))
}

func (bs *bigStruct) an() *C.smallStruct_t {
    return (*C.smallStruct_t)(unsafe.Pointer(uintptr(bs.instance) + C.sizeof_int))
}

func (bs *bigStruct) an_u() []byte {
    // cgo having same thought about and takes smallStruct_t.u as array
    return (*C.smallStruct_t)(unsafe.Pointer(uintptr(bs.instance) + C.sizeof_int)).u[:]
}

func (bs *bigStruct) next_field_after_un_t() *Type {
    return (*Type)(unsafe.Pointer(uintptr(bs.instance) + C.sizeof_int + C.sizeof_smallStruct_t))
}
...