Go/CGo-如何使用作为指针传递的C数组



我把它作为一个问题/答案发布,因为我花了一段时间才解决,我不介意对我的解决方案进行一些反馈。在Go/CGo中,如何处理作为指针传递的C数组?

例如,使用这个C结构:

struct _GNetSnmpVarBind {                     
    guint32     *oid;       /* name of the variable */
    gsize       oid_len;    /* length of the name */
    ... and other fields
};  

我想将oid字段转换为Go字符串,如何使用guint32*指针?

您可以使用我在Go wiki 中看到的技巧将C数组转换为Go切片

未经测试,但希望你能明白!不要让切片的寿命比C数据长,因为它直接指向它。

上次我使用它时,我看了一下反汇编,它生成了非常高效的代码。

func gIntArrayOidString(oid *_Ctype_guint32, oid_len _Ctype_gsize) (result string) {
    var oids []uint32
    sliceHeader := (*reflect.SliceHeader)((unsafe.Pointer(&oids)))
    sliceHeader.Cap = oid_len
    sliceHeader.Len = oid_len
    sliceHeader.Data = uintptr(unsafe.Pointer(oid))
    var result string
    for _, value := range oids {
        result += fmt.Sprintf(".%d", value)
    }
    return result[1:]
}

我这样做的方法是找到要读取的字节数(guint32*oid_len的大小),然后进行二进制运算。读取()字节数,然后循环通过大小为块的be字节。回想起来很容易;困难的部分是让类型转换工作起来,因为Go比C.更严格

例如,下面是将guint32*转换为Go字符串(表示SNMP OID)的Go代码:

func gIntArrayOidString(oid *_Ctype_guint32, oid_len _Ctype_gsize) (result string) {
    size := int(unsafe.Sizeof(*oid))
    length := int(oid_len)
    gbytes := C.GoBytes(unsafe.Pointer(oid), (_Ctype_int)(size*length))
    buf := bytes.NewBuffer(gbytes)
    for i := 0; i < length; i++ {
        var out uint32
        if err := binary.Read(buf, binary.LittleEndian, &out); err == nil {
            result += fmt.Sprintf(".%d", out)
        } else {
            return "<error converting oid>"
        }
    }
    if len(result) > 1 {
        return result[1:] // strip leading dot
    }
    return "<error converting oid>"
}

评论?


上下文:代码来自gsnmpgo。

我假设gsnmp中的值不一定是小端序,而是本机字节顺序。我只会使用不安全的。用于遍历数组的Sizeof。例如

package main
import (
    "unsafe"
    "fmt"
)
var ints = [...]int32 {1, 2, 3}
func main() {
    var result string
    var p *int32 = &ints[0]
    for i := 0; i < len(ints); i++ {
        result += fmt.Sprintf(".%d", *p)
        p = (*int32)(unsafe.Pointer(uintptr(unsafe.Pointer(p))+unsafe.Sizeof(*p)))
    }
    fmt.Println(result[1:])
}

最新更新