將c語言的結構體定義變成對應的golang語言的結構體定義,並將golang語言結構體變量的指針傳遞給c語言,cast C struct to Go struct


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{})
}

其中的 _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.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 <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
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM