c言語の構造体定義を対応するgolang言語の構造体定義に変更し、golang言語の構造体変数のポインタをc言語に渡します.cast C struct to Go struct...

11700 ワード

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
", C.struct_CType{}) }

その中の_Ctype_struct_CTypeは寒気が少しおかしくて、最初は慌てなくても、後の方法で自動的にこの奇妙な名前を得ることができます.
もちろん、上の説明はc structのために内蔵関数を定義することだけです.golangでc structを印刷するだけなら、普通の変数のようにPrintに直接伝えるだけでいいです.例えば、fmt.Printf("%v",C.objstruct)またはfmt.Println(C.objstruct).
 
2、golang全体の構造体ポインタをc言語の構造体ポインタに変換することができます.前提はgolangの構造体とcの構造体定義が1つ1つ対応していることです(後で、どのように着て1つ対応する構造体を紹介します)が、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、上記の第2歩のやり方は安全ではありません.このようなプログラマーが自分で定義した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 
*/
import "C"
 
type File C.FILE
const 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 

typedef struct {
    int a;
    int b;
} Foo;

void pass_struct(Foo *in) { printf("%d : %d
", 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
", 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
}

 
転載先:https://www.cnblogs.com/welhzh/p/9108603.html