英文:
Pass struct and array of structs to C function from Go
问题
遇到了这个问题。只能获取传递结构的第一个成员...我做错了什么?从Go语言传递结构的正确方法是什么?
这是一个不起作用的示例:
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}}
// 错误的结果 = [25, 0]
C.pass_struct((*C.Foo)(unsafe.Pointer(&foo)))
// 完全不起作用,SIGSEGV
// C.pass_array((**C.Foo)(unsafe.Pointer(&foos[0])))
// 错误的结果 = [25, 0], [50, 0]
out := make([]*C.Foo, len(foos))
out[0] = (*C.Foo)(unsafe.Pointer(&foos[0]))
out[1] = (*C.Foo)(unsafe.Pointer(&foos[1]))
C.pass_array((**C.Foo)(unsafe.Pointer(&out[0])))
}
英文:
Stuck with this problem. Able to get only the first member of passed structure... What I do wrong? And what is the right way to pass the structure from Go to C?
This is my example of how it doesn't work:
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])))
}
答案1
得分: 8
问题在于Foo
和_Ctype_Foo
是不同的结构体。
我猜测你在64位系统上运行。请注意,在Go语言中,int
是64位的,但在C语言中很可能是32位的。
如果我将Foo
的定义更改为以下内容,那么它在我的机器上可以工作(64位Linux):
type Foo struct {
A int32
B int32
}
然而,我认为这可能会引发麻烦。你可以让你的Go和C代码使用相同的结构体,如下所示:
type Foo _Ctype_Foo
英文:
The problem is that Foo
and _Ctype_Foo
are different structures.
I would guess you are running on 64 bit. Note that int
is 64 bit in go, but is quite likely to be 32 bit in C.
If I change the definition of Foo
to this then it works on my machine (64 bit linux)
type Foo struct {
A int32
B int32
}
However I would say that is a recipe for trouble - make your Go and C code use the same structure with
type Foo _Ctype_Foo
答案2
得分: 7
我知道这是一个相当旧的话题,但我偶然发现了它。这是一个修改过的(正确的)版本,其中包含了一些来自C语言对Go结构体的额外操作。
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
英文:
I know this is a fairly old topic but I stumbled across it. Here's a modified (correct) version with some additional manipulation from C land on the Go structs.
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
答案3
得分: 7
这两个答案现在都不适用(至少在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()
}
英文:
Neither of these answers work now (at least under Go 1.12). I wrote two another solutions:
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()
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论