我将此作为问题/答案发布,因为我花了一段时间才解决问题,我不介意对我的解决方案提出一些反馈意见.在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的大小),然后对字节数执行binary.Read(),然后循环遍历大小块中的字节。回顾起来容易;困难的部分是让类型转换正常工作,因为 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。
| 归档时间: | 
 | 
| 查看次数: | 7402 次 | 
| 最近记录: |