zoukankan      html  css  js  c++  java
  • 将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
    ", 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 的结构体定义是一一对应的(后面有介绍怎么穿件一一对应的结构体),但是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
    ", 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
    }
  • 相关阅读:
    《Maven实战》文字版[PDF]
    spring管理的类如何调用非spring管理的类
    从session中获取当前用户的工具类
    WebService,ESB笔记
    Activiti
    ElasticSearch最全分词器比较及使用方法
    [ElasticSearch]Java API 之 滚动搜索(Scroll API)
    从html富文本中提取纯文本
    Jetty启动报Error scanning entry META-INF/versions/9/org/apache/logging/log4j/util/ProcessIdUtil.class
    elasticsearch: 创建mapping
  • 原文地址:https://www.cnblogs.com/welhzh/p/9108603.html
Copyright © 2011-2022 走看看