将具有uint8_t * num的C结构转换为Go

时间:2018-06-28 22:18:13

标签: go cgo

C结构:

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

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

包装纸:

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])),
   }
}

如何从go包装器访问uint8_t *num? 我认为定义的方法不正确。 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 :(得分:0)

在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]
相关问题