8

解決するのに時間がかかったので、これを質問/回答として投稿しています。私の解決策に関するフィードバックは気にしません。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* ポインターをどのように操作すればよいですか?

4

3 に答える 3

6

go wiki で見たヒントを使用して、C 配列を Go スライスに変換できます。

テストされていませんが、うまくいけばアイデアが得られます! スライスは直接 C データを指しているため、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:]
}
于 2013-02-12T08:15:28.913 に答える
4

私が行った方法は、読み取るバイト数 (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からのものです。

于 2013-02-12T05:53:55.787 に答える