从Raspberry PI上的GO程序中,我正在尝试调用一个函数(将Matlab函数转换为C函数),并且该函数的输入是指向结构的指针,而该结构包含指向double(data)的指针以及一个指向int(size)和两个int(allocatedSize,numDimensions)的指针。我尝试了几种方法,但是没有任何效果,当我通过编译后,通常会出现恐慌:运行时错误:运行程序时,cgo参数将Go指针指向Go指针。
sumArray.c
/*sumArray.C*/
/* Include files */
#include "sumArray.h"
/* Function Definitions */
double sumArray(const emxArray_real_T *A1)
{
double S1;
int vlen;
int k;
vlen = A1->size[0];
if (A1->size[0] == 0) {
S1 = 0.0;
} else {
S1 = A1->data[0];
for (k = 2; k <= vlen; k++) {
S1 += A1->data[k - 1];
}
}
return S1;
}
sumArray.h
#ifndef SUMARRAY_H
#define SUMARRAY_H
/* Include files */
#include <stddef.h>
#include <stdlib.h>
#include "sumArray_types.h"
/* Function Declarations */
extern double sumArray(const emxArray_real_T *A1);
#endif
sumArray_types.h
#ifndef SUMARRAY_TYPES_H
#define SUMARRAY_TYPES_H
/* Include files */
/* Type Definitions */
#ifndef struct_emxArray_real_T
#define struct_emxArray_real_T
struct emxArray_real_T
{
double *data;
int *size;
int allocatedSize;
int numDimensions;
};
#endif /*struct_emxArray_real_T*/
#ifndef typedef_emxArray_real_T
#define typedef_emxArray_real_T
typedef struct emxArray_real_T emxArray_real_T;
#endif /*typedef_emxArray_real_T*/
#endif
/* End of code generation (sumArray_types.h) */
main.go
// #cgo CFLAGS: -g -Wall
// #include <stdlib.h>
// #include "sumArray.h"
import "C"
import (
"fmt"
)
func main() {
a1 := [4]C.Double{1,1,1,1}
a2 := [1]C.int{4}
cstruct := C.emxArray_real_T{data: &a1[0], size: &a2[0]}
cstructArr := [1]C.emxArray_real_T{cstruct}
y := C.sumArray(&cstructArr[0])
fmt.Print(float64(y))
}
在此示例中,我感到恐慌:运行时错误:运行程序时,cgo参数具有指向Go指针的Go指针。
我不怎么使它工作或是否有可能使它工作。我希望有人能帮助我或就如何解决这个问题提供指导。
答案 0 :(得分:0)
太多评论了,所以这里就是答案。
首先,原始文本:
一个直接的解决方案是使用C.malloc(4 * C.sizeof(C.double))
分配double
-s的数组。请注意,完成后必须确保对其调用C.free()
。单个int
的第二个数组也是如此。
现在,您对Mattanis的评论进行了重新格式化:
感谢您提供一些指导。我尝试过
a1 := [4]C.double{1,1,1,1} sizeA1 := C.malloc(4 * C.sizeof_double) cstruct := C.emxArray_real_T{ data: &a1[0], size: (*C.int)(sizeA1) } y := C.sumArray(cstruct) defer C.free(sizeA1)
但是它给了我同样的感觉 像以前一样回答cgo参数 当我有Go指针到Go指针时 试图运行程序
您似乎仍然错过了关键点。使用cgo
时,有两个 disjoint “内存视图”:
“ Go内存”是Go运行时分配的所有内容,它们为运行的进程提供动力-代表该进程。 GC知道这种内存(大多数情况下,除非有怪异的技巧),这是运行时的一部分。
“ C内存”是C代码分配的内存,通常是通过调用libc
的{{1}} / malloc()
来实现的。
现在想象一个不太遥不可及的场景:
因此,您有一个相当经典的场景,在这种情况下,您会获得一个非常简单的情况,即不同步并行内存访问,这肯定会在当今的多核多插槽硬件上遭受灾难。
还认为Go是比C更高级的编程语言。它至少具有自动垃圾回收功能,请注意,the Go spec中没有任何内容指定必须精确指定GC的方式。 这意味着Go的特定实现(包括将来的参考代码)可以自由地允许其GC在内存中移动任意对象¹,这意味着更新指向内存块的每个指针移至原位置后,指向该块新位置中的同一位置。
考虑到这些注意事项,Go开发人员假定为了使realloc()
-使用的程序永不过时,²禁止将包含指向其他Go内存块的指针的任何内存块传递给C。 / p>
尽管可以传递包含指向C内存的指针的Go内存块。
回到第二个示例中,
您仍然在Go内存中分配了4个cgo
,double
数组。
然后,语句a1
再次在Go内存中分配cstruct := C.emxArray_real_T{...}
的实例,因此,在使用指向Go内存的指针初始化C.emxArray_real_T
字段之后,data
),然后将其地址传递给C端,运行时会在实际调用C端并使程序崩溃之前执行其动态检查。
¹例如,这是所谓的“世代”垃圾收集器的典型行为。
²也就是说,您使用同一“主要”版本的Go编译器的将来版本重新编译程序,并且程序可以继续运行,而无需进行修改。