2014-04-11 49 views
3

我使用cgo來開發來自Go的庫結合。 讓我考慮下面的C結構和Go結構。好的或推薦的方法來將C結構轉換成結構

struct cons_t { 
    size_t type; 
    cons_t *car; 
    cons_t *cdr; 
}; 

cons_t* parse(const char *str); 

,這是去的結構

type Cons struct { 
    type int; 
    car *Cons; 
    cdr *Cons; 
} 

對於如下實施去功能,什麼是實現TranslateCCons2GoCons更好的辦法?

func Parse (str string) *Cons { 
    str_ptr := C.CString(string); 
    cons_ptr := C.parse(str_ptr); 
    retCons := TranslateCCons2GoCons(cons_ptr); 
    return retCons; 
} 

我的第一個答案如下。

/*#cgo 
int getType(cons_t *cons) { 
    return cons->type; 
} 
cons_t *getCar(cons_t *cons) { 
    return cons->car; 
} 
cons_t *getCdr(cons_t *cons) { 
    return cons->cdr; 
} 
*/ 

func TranslateCCons2GoCons (c *C.cons_t) Cons { 
    type := C.getType(c); 
    car := C.getCar(c); 
    cdr := C.getCdr(c); 
    // drop null termination for simplicity 
    return Cons{type, TranslateCCons2GoCons(car), TranslateCCons2GoCons(cdr)}; 
} 

有沒有更好的辦法?

回答

0

我會建議不要存取功能。你應該能夠直接訪問C結構的字段,這將避免Go - > C函數調用開銷(這是不重要的)。所以,你可以使用這樣的:

func TranslateCCons2GoCons (c *C.cons_t) *Cons { 
    if c == nil { 
     return nil 
    } 
    return &Cons{ 
     type: int(c.type), 
     car: TranslateCCons2GoCons(c.car), 
     cdr: TranslateCCons2GoCons(c.cdr), 
    } 
} 

另外,如果你分配一個C字符串C.CString,你需要釋放它。所以你的Parse功能應該看起來像這樣:

func Parse (str string) *Cons { 
    str_ptr := C.CString(str) 
    defer C.free(unsafe.Pointer(str_ptr) 
    cons_ptr := C.parse(str_ptr) 
    retCons := TranslateCCons2GoCons(cons_ptr) 
    // FIXME: Do something to free cons_ptr here. The Go runtime won't do it for you 
    return retCons 
} 
+0

當然,如果它沒有被'parse'存儲,你只能釋放它。 :)在這種情況下,您通常將CString存儲在未導出的字段中,稍後再調用'C.free'。 – LinearZoetrope

+0

@JamesHenstridge謝謝你。這似乎更簡單。 – shinpei

1

你可以在Go中使用C結構(儘管如果struct擁有union它會變得更復雜一點)。最簡單的方法也只是

type Cons struct { 
    c C.cons_t 
} 

用C的任何功能,現在只需在Go

func Parse(s string) Cons { 
    str := C.CString(s) 
    // Warning: don't free this if this is stored in the C code 
    defer C.free(unsafe.Pointer(str)) 
    return Cons{c: C.parse(str)} 
} 

這有它自己的開銷直通,因爲你必須做元素訪問類型轉換。所以,現在是什麼var c Cons{}; c.Type之前

func (c Cons) Type() int { 
    return int(c.c.type) 
} 

您存儲旁邊的C類爲方便域的中間妥協可以用來

type Cons struct { 
    type int 
    c C.cons_t 
} 

func (c *Cons) SetType(t int) { 
    c.type = t 
    c.c.type = C.size_t(t) 
} 

func (c Cons) Type() int { 
    return c.type 
} 

這個唯一真正的問題是,如果你是調用C功能很多,這可以在設定的Go-側田推出的維護開銷:

func (c *Cons) SomeFuncThatAltersType() { 
    C.someFuncThatAltersType(&c.c) 
    c.Type = int(c.c.type) // now we have to remember to do this 
} 
+0

是的,通過c函數訪問每次似乎很難維護我也是。像中間的方式更好。 – shinpei