2013-02-12 7 views
5

Zamieszczam to jako pytanie/odpowiedź, ponieważ zajęło mi trochę czasu, aby wypracować, i nie miałbym nic przeciwko temu, aby uzyskać opinię na temat mojego rozwiązania . W Go/CGo, jak pracujesz z tablicą C przekazaną jako wskaźnik?Go/CGo - jak używać tablicy C podanej jako wskaźnik

Na przykład, w tym C struct:

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

chcę przekonwertować OID na ciąg Go, jak będę pracować z guint32 * wskaźnik?

Odpowiedz

4

Sposób w jaki to zrobiłem to znaleźć liczbę bajtów do odczytania (rozmiar guint32 * oid_len), następnie zrobił binary.Read() na liczbę bajtów, a następnie zapętlił się bajtami w kawałkach rozmiar. Łatwo z perspektywy czasu; Najtrudniejsze było coraz konwersje typu pracy jak Go jest bardziej restrykcyjne niż C.

Na przykład tutaj jest kod Go do zamiany guint32 * na ciąg Go (reprezentujący SNMP OID):

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

Komentarze ?


Kontekst: kod pochodzi z gsnmpgo.

2

Zakładam, że wartości z gsnmp niekoniecznie znajdują się w little-endian, ale w natywnej kolejności bajtów. Po prostu użyłbym niebezpiecznego.Sizeof do iteracji poprzez tablicę. na przykład

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

Dzięki Axw, sprawdzę to. –

3

Można konwertować tablicę C do plasterka Go używając a tip I saw in the go wiki

Nietestowane ale mam nadzieję, że masz pomysł! Nie pozwól, aby plasterek żył dłużej niż dane C, ponieważ wskazuje bezpośrednio na niego.

Ostatni raz użyłem tego, spojrzałem na demontaż i wygenerowałem bardzo sprawny kod.

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

Dokładnie tego szukam! –

+0

Od 2015 roku zostało to usunięte z wiki, ponieważ "nie można go używać bezpiecznie ani przenośnie". – psanford

Powiązane problemy