2013-02-12 8 views
5

Ich poste dies als Frage/Antwort, da es eine Weile gedauert hat zu trainieren, und ich hätte nichts gegen ein Feedback zu meiner Lösung . Wie arbeiten Sie in Go/CGo mit einem C-Array, das als Zeiger übergeben wird?Go/CGo - Wie benutzt man ein C-Array, das als Zeiger übergeben wurde

Zum Beispiel mit dieser C-Struktur:

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

I oid Feld zu einem Go-String konvertieren will, wie würde ich mit dem guint32 arbeiten * Zeiger?

Antwort

4

Die Art, wie ich es getan habe, war die Anzahl der zu lesenden Bytes (Größe eines Guint32 * oid_len) zu finden, dann eine binary.Read() auf die Anzahl der Bytes, dann durchlaufen Bytes in Blöcken von Größe. Im Nachhinein einfach; der schwierige Teil war immer die Typkonvertierungen als Go arbeiten, ist strenger als C.

Denn hier Beispiel ist der Code Go die guint32 * zu einem Go-String (die ein SNMP-OID) zum Umwandeln:

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>" 
} 

Kommentare ?


Kontext: Der Code ist von gsnmpgo.

2

Ich nehme an, die Werte von gsnmp sind nicht unbedingt in Little-Endian, sondern die native Byte-Reihenfolge. Ich würde nur unsafe.Sizeof verwenden, um durch das Array zu iterieren. z.B.

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

Danke Axw, ich werde es überprüfen. –

3

Sie können den C-Array in eine Go Scheibe mit a tip I saw in the go wiki

Ungeprüfte konvertieren, aber hoffentlich bekommen Sie die Idee! Lassen Sie die Scheibe jedoch nicht länger leben als die C-Daten, da sie direkt in die Scheibe zeigt.

Als ich das letzte Mal benutzt habe, habe ich mir die Disassemblierung angeschaut und einen sehr effizienten Code generiert.

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

Genau das suche ich! –

+0

Ab 2015 wurde dies aus dem Go-Wiki entfernt, weil "es nicht sicher oder portabel verwendet werden kann". – psanford