2013-02-12 32 views
5

我發佈這個問題/答案,因爲它花了我一段時間的工作,我不介意對我的解決方案的一些反饋。在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字段轉換爲字符串去,我怎麼會與guint32 *指針工作?

回答

4

我這樣做的方式是找到要讀取的字節數(guint32 * oid_len的大小),然後在字節數上做了binary.Read(),然後循環遍歷字節尺寸。容易回想起來;硬的部分就是類型轉換的工作作爲圍棋是比C

嚴格例如,以下是爲guint32 *轉換爲圍棋串(表示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

2

我假設來自gsnmp的值不一定是小端,而是本地字節順序。我只是使用unsafe.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:]) 
} 
+0

謝謝Axw,我會檢查出來。 – 2013-12-05 23:09:08

3

你可以C數組轉換成細末片使用a tip I saw in the go wiki

未經測試,但希望你的想法!不要讓切片比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:] 
} 
+0

這正是我要找的! – 2016-08-06 18:40:00

+0

截至2015年,這已從go wiki中刪除,因爲「它無法安全或便攜地使用」。 – psanford 2017-06-22 20:55:24

相關問題