Преобразовать структуру C с uint8_t * num в Go - PullRequest
0 голосов
/ 29 июня 2018

C структура:

typedef struct info_s {
     int len;
     uint8_t *num;
}info_t;

extern int info_collect(int unit, info_t *info,
                        data_t *data);

Go Wrapper:

type Info struct {
    Len     int
    num     []uint8
}

//Method to convert C.info_t => Info

func (inf C.info_s) Info() Info {

   var tInf Info

   tInf.Len = int(inf.len)
   for i := 0; i < int(tInf.Len); i++ {
     tInf.num[i] = uint8(inf.num[i])
   }

   return Info{
     Len: int(inf.len),
     Info: (*C.uchar)(unsafe.Pointer(&info.num[0])),
   }
}

Как мне получить доступ к uint8_t *num из go wrapper? Я не думаю, что метод определен правильно. Является ли структура для num - (num []uint8) правильным способом доступа к этому?

Добавление недостающего фрагмента головоломки. В C также есть API, который принимает структуру C в качестве входных данных.

Теперь, когда я вызываю этот API, у меня возникает паника во время выполнения:

data := []uint8{1, 2, 3}

var inf = new(C.info_t)

inf.len = 64
inf.num = data

C.info_collect(C.int(unit), (*C.info_t)(unsafe.Pointer(&info)),
                            (*C.data_t)(unsafe.Pointer(&data)))

Panic: runtime error: cgo argument has Go pointer to Go pointer

1 Ответ

0 голосов
/ 29 июня 2018

В Go num - это просто фрагмент типа []uint8 (или его псевдоним []byte) длины len(num). Чтобы скопировать данные из типа C info_t в управляемую память типа Go []uint8, напишите функцию Go num:

package main

import (
    "fmt"
    "unsafe"
)

/*
#include <stdint.h>
typedef struct info_s {
    int len;
    uint8_t *num;
} info_t;
*/
import "C"

func num(info C.info_t) []uint8 {
    n := make([]uint8, 0, info.len)
    for i := _Ctype_int(0); i < info.len; i++ {
        u8 := *(*uint8)(unsafe.Pointer(uintptr(unsafe.Pointer(info.num)) + uintptr(i)))
        n = append(n, u8)
    }
    return n
}

func main() {
    test := []uint8{1, 2, 3}
    fmt.Println(len(test), test)

    info := C.info_t{
        len: _Ctype_int(len(test)),
        num: (*_Ctype_uint8_t)(&test[0]),
    }
    infonum := (*[1 << 20]uint8)(unsafe.Pointer(info.num))[:info.len]
    fmt.Println(info.len, infonum)

    n := num(info)
    fmt.Println(len(n), n)
}

Выход:

3 [1 2 3]
3 [1 2 3]
3 [1 2 3]
...