10

卡住了这个问题。只能获得传递结构的第一个成员......我做错了什么?将结构从 Go 传递到 C 的正确方法是什么?

这是我如何不起作用的示例:

package main

/*
#include <stdio.h>

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

void pass_array(Foo **in) {
    int i;

    for(i = 0; i < 2; i++) {
        fprintf(stderr, "[%d, %d]", in[i]->a, in[i]->b);
    }
    fprintf(stderr, "\n");
}

void pass_struct(Foo *in) {
    fprintf(stderr, "[%d, %d]\n", in->a, in->b);
}

*/
import "C"

import (
    "unsafe"
)

type Foo struct {
    A int
    B int
}

func main() {

    foo := Foo{25, 26}
    foos := []Foo{{25, 26}, {50, 51}}

    // wrong result = [25, 0]
    C.pass_struct((*_Ctype_Foo)(unsafe.Pointer(&foo)))

    // doesn't work at all, SIGSEGV
    // C.pass_array((**_Ctype_Foo)(unsafe.Pointer(&foos[0])))

    // wrong result = [25, 0], [50, 0]
    out := make([]*_Ctype_Foo, len(foos))
    out[0] = (*_Ctype_Foo)(unsafe.Pointer(&foos[0]))
    out[1] = (*_Ctype_Foo)(unsafe.Pointer(&foos[1]))
    C.pass_array((**_Ctype_Foo)(unsafe.Pointer(&out[0])))
}
4

3 回答 3

7

问题是Foo_Ctype_Foo是不同的结构。

我猜你是在 64 位上运行的。请注意,int在 go 中是 64 位,但在 C 中很可能是 32 位。

如果我将定义更改Foo为此,那么它可以在我的机器上运行(64 位 linux)

type Foo struct {
    A int32
    B int32
}

但是我会说这是一个麻烦的秘诀 - 让你的 Go 和 C 代码使用相同的结构

type Foo _Ctype_Foo
于 2013-11-11T16:38:12.183 回答
6

我知道这是一个相当古老的话题,但我偶然发现了它。这是一个修改(正确)版本,在 Go 结构上从 C 语言进行了一些额外的操作。

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

输出:

from C land
10 : 20
1 : 2
3 : 4
a & b should have incremented with 1
from Go land
2 : 3
4 : 5
于 2014-12-03T12:06:53.927 回答
6

这些答案现在都不起作用(至少在 Go 1.12 下)。我写了另外两个解决方案:

package main

/*
#include <stdio.h>
#include <stdlib.h>

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

int pass_array(Foo **in) {
    int i;
    int r = 0;

    for(i = 0; i < 2; i++) {
        r += in[i]->a;
        r *= in[i]->b;
    }
    return r;
}

*/
import "C"
import (
    "fmt"
    "unsafe"
)

type Foo struct {
    A int32
    B int32
}

func a() {
    foos := []Foo{{1, 2}, {3, 4}}

    l := len(foos)
    values := (*[1 << 28]*C.Foo)(C.malloc(C.size_t(C.sizeof_Foo * l)))
    for i, f := range foos {
        foo := (*C.Foo)(C.malloc(C.size_t(C.sizeof_Foo)))
        (*foo).a = C.int(f.A)
        (*foo).b = C.int(f.B)
        values[i] = foo
    }
    val := C.pass_array(&values[0])
    for i := 0; i < l; i++ {
        C.free(unsafe.Pointer(values[i]))
    }
    C.free(unsafe.Pointer(values))
    fmt.Println("A finished", val)
}

func b() {
    foos := []Foo{{5, 6}, {7, 8}}

    values := make([]*C.Foo, len(foos))
    for i, f := range foos {
        p := (*C.Foo)(C.malloc(C.size_t(C.sizeof_Foo)))
        values[i] = p
        (*p).a = C.int(f.A)
        (*p).b = C.int(f.B)
    }
    val := C.pass_array(&values[0])
    for _, v := range values {
        C.free(unsafe.Pointer(v))
    }
    fmt.Println("B finished", val)
}

func main() {
    a()
    b()
}
于 2019-05-14T19:11:30.580 回答