2013-02-12 20 views
5

Tôi đăng câu hỏi này như một câu hỏi/câu trả lời, vì tôi mất một thời gian để giải quyết. . Trong Go/CGo, làm thế nào để bạn làm việc với một mảng C được truyền như một con trỏ?Go/CGo - làm thế nào để bạn sử dụng một mảng C được chuyển thành con trỏ

Ví dụ, với C struct này:

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

Tôi muốn chuyển đổi lĩnh vực oid thành một chuỗi Go, làm thế nào tôi sẽ làm việc với các guint32 * con trỏ?

Trả lời

4

Cách tôi đã làm là tìm số byte cần đọc (kích thước của một guint32 * oid_len), sau đó đã thực hiện một binary.Read() trên số byte, sau đó lặp lại là byte theo khối kích thước. Dễ nhìn lại; phần cứng đã nhận được sự chuyển đổi kiểu làm việc như Go là nghiêm ngặt hơn C.

Ví dụ ở đây là mã Go để chuyển đổi các guint32 * một chuỗi Go (đại diện cho một 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>" 
} 

Comments ?


Bối cảnh: mã này là từ gsnmpgo.

2

Tôi giả định các giá trị từ gsnmp không nhất thiết phải ở mức nhỏ, nhưng thứ tự byte gốc. Tôi sẽ chỉ sử dụng unsafe.Sizeof để lặp qua mảng. ví dụ.

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

Cảm ơn Axw, tôi sẽ kiểm tra. –

3

Bạn có thể chuyển đổi các mảng C vào một lát Go sử dụng a tip I saw in the go wiki

chưa được kiểm tra nhưng hy vọng bạn sẽ có được ý tưởng! Đừng để slice tồn tại lâu hơn dữ liệu C mặc dù nó trỏ trực tiếp vào nó.

Thời gian qua tôi đã sử dụng tính năng này, tôi đã xem xét việc tháo gỡ và tạo ra mã rất hiệu quả.

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

Đây chính xác là những gì tôi đang tìm kiếm! –

+0

Tính đến năm 2015, điều này đã bị xóa khỏi wiki đi vì "nó không thể được sử dụng một cách an toàn hoặc có thể di chuyển được". – psanford

Các vấn đề liên quan