https://groups.google.com/forum/#!topic/golang-nuts/JkvR4dQy9t4
https://golang.org/misc/cgo/gmp/gmp.go
https://stackoverflow.com/questions/19910647/pass-struct-and-array-of-structs-to-c-function-from-go
https://studygolang.com/articles/6367
1、可以為c struct定義結構體函數,如下定義的列印函數,(你可能還可以定義改變結構體內部子field的函數,但我未驗證過):
working with a lot of typedefs in cgo is a real pain (Go's typing rules are simply too strictfor a C programmer).I'd suggest you create a wrapper function in C (or Go) to create the structure for you. for printing, you can define the String method on real type of structure (it won't be portable,as it depends the real type name of the C struct, but it's certainly doable, and will save youa lot of work if you're debugging a C-Type-rich application)For example,
package main /*struct CType { int a; char b; float c;};*/import "C" import "fmt" func (c _Ctype_struct_CType) String() string { return "hello" } func main() { fmt.Printf("%v\n", C.struct_CType{})}
其中的 _Ctype_struct_CType 寒氣來有點奇怪,起始不用驚慌,可以用後面的方法自動得到這種奇怪的命名的。
當然,上面的只是示範為 c struct 定義內建函數。如果你僅僅是在golang中列印 c struct,只需要像普通變數一樣直接傳給Print就可以了,如: fmt.Printf("%v\n", C.objstruct) 或 fmt.Println(C.objstruct)。
2、你可以將整個golang的結構體指標轉換成c語言的結構體指標,前提是golang 的結構體和c 的結構體定義是一一對應的(後面有介紹怎麼穿件一一對應的結構體),但是c語言的結構體指標無法直接轉換成golang語言的結構體指標:
You can cast the entire struct via intermediate pointers. The conversion should work in either direction. There are probably other ways too, like encoding/binary. An example of the pointer approach follows:
package main import ( "fmt" "unsafe") // struct x {// int y, z;// };//// int sum(struct x a) {// return a.y + a.z;// }//import "C" type X struct{ Y, Z int32 } func main() { a := &X{5, 7} fmt.Println(a, "->", C.sum(*((*C.struct_x)(unsafe.Pointer(a)))))
}
3、上面第二步的做法並不安全,因為這種程式員自己定義的golang語言結構體可能和c語言的結構體並不一一對應,因此應該用下面的方法:This is not safe and Go doesn't guarantee compatible struct layout rules with gcc. for example, 8g currently aligns uint64 only to 4-byte boundary, but gcc aligns it to 8-byte boundary.If you want compatible structure layout, you can use "cgo -godefs". for example, given file.go:
package main /*#include <stdio.h>*/import "C" type File C.FILEconst Sizeof_File = C.sizeof_FILE
go tool cgo -godefs file.go will generate a Go definition of type File that matches that of C's FILE.
cgo -godefs 是專門用來將c語言結構體轉換成golang語言對應的結構體的工具。
4、樣本:
package main/*#include <stdio.h>typedef struct { int a; int b;} Foo;void pass_struct(Foo *in) { printf("%d : %d\n", in->a, in->b); }void pass_array(Foo **in, int len) { for(int i = 0; i < len; i++) { pass_struct(in[i]); in[i]->a += 1; in[i]->b += 1; }}*/import "C"import ( "fmt" "unsafe")type Foo struct{ a, b int32 }func main() { foo := Foo{10, 20} foos := []*Foo{&Foo{1, 2}, &Foo{3, 4}} fmt.Println("from C land") C.pass_struct((*C.Foo)(unsafe.Pointer(&foo))) C.pass_array((**C.Foo)(unsafe.Pointer(&foos[0])), C.int(len(foos))) fmt.Println("a & b should have incremented with 1") fmt.Println("from Go land") for _, foo := range foos { fmt.Printf("%d : %d\n", foo.a, foo.b) }}
Output:
from C land10 : 201 : 23 : 4a & b should have incremented with 1from Go land2 : 34 : 5
5、樣本2:
將c語言的 char * 指標copy成 golang 的byte slice:
// convert c language char* to golang byte slice, and COPY source datas into dest slice packet *C.char // 該變數在c語言裡賦值 vlen := 512 b := make([]byte, vlen) ii := C.int(0) for i := 0; i < vlen; i++ { ii = C.int(i) // this is copy, not equal to the orignal pointer b[i] = *(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(packet)) + uintptr(unsafe.Pointer(C.int_to_charp(ii))))) }
我自己的轉換的樣本:
c語言定義的結構體:
struct dnet_host { struct dnet_key key; char name[DNET_HOST_NAME_MAX]; char version[16]; time_t last_active; time_t last_appear; time_t last_time_changed; uint32_t crc32; uint32_t route_ip; unsigned name_len; uint16_t route_port; uint8_t is_local; uint8_t is_trusted; enum dnet_host_route_types route_type;};
轉成golang對應的結構體 (type DH C.struct_dnet_host):
type DH struct { Key _Ctype_struct_dnet_key Name [256]int8 Version [16]int8 Last_active int64 Last_appear int64 Last_time_changed int64 Crc32 uint32 Route_ip uint32 Name_len uint32 Route_port uint16 Is_local uint8 Is_trusted uint8 Route_type uint32 Pad_cgo_0 [4]byte}