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 strict
for 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 you
a 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{})
}
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语言的结构体并不一一对应,因此应该用下面的方法:
package main
 
/*
#include <stdio.h>
*/
import "C"
 
type File C.FILE
const Sizeof_File = C.sizeof_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 land
10 : 20
1 : 2
3 : 4
a & b should have incremented with 1
from Go land
2 : 3
4 : 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
}