正确的Go类型传递给C函数? [英] Correct Go type to pass to C function?
问题描述
我正在将用C语言编写的一些服务器代码移植到Go上,并且它使用了我真的不想重写的加密库.相反,我尝试使用Cgo编写包装程序,以便我的其余代码可以更轻松地调用它.这是lib标头的一部分:
I'm porting some server code I wrote in C over to Go and it uses an encryption library I really don't want to rewrite. Instead I'm trying to use Cgo to write a wrapper so that the rest of my code can call it more easily. Here's part of the header for the lib:
// encryption/encryption.h
#define CRYPT_BBCFG 1
typedef struct {
// ...bunch of fields...
uint32_t bb_posn;
} CRYPT_SETUP;
int CRYPT_CreateKeys(CRYPT_SETUP* cs, void* key, unsigned char type);
这是我要开始使用的概念验证代码段:
And here's the proof-of-concept snippet I'm trying to get to work:
package goserv
//#include "encryption/encryption.h"
import "C"
func main() {
cdata := new(C.struct_CRYPT_SETUP)
key := make([]byte, 48)
C.CRYPT_CreateKeys(cdata, &key, C.CRYPT_BLUEBURST)
}
我在标头中定义了一个测试函数( int test(){return 1;}
),从我的代码中调用该函数没有问题(通过 C.test()
),也没有引用任何#defined'd常量( C.CRYPT_BBCFG
),但是当我尝试运行 go install goserv 时,出现以下错误:
I defined a test function (int test() { return 1; }
) in the header and have no problem calling that from my code (via C.test()
) nor referencing any of the #defined'd constants (C.CRYPT_BBCFG
) but get the following error when I attempt to run go install goserv:
Undefined symbols for architecture x86_64:
"_CRYPT_CreateKeys", referenced from:
__cgo_e89359206bf1_Cfunc_CRYPT_CreateKeys in goserv.cgo2.o
(maybe you meant: __cgo_e89359206bf1_Cfunc_CRYPT_CreateKeys)
ld: symbol(s) not found for architecture x86_64
在这一点上,我假设我只是没有使用正确的参数调用该函数.我的印象是cdata的类型为 * C.struct_CRYPT_SETUP
,密钥应为 * byte
(尽管没有&也不起作用)和C.CRYPT_BLUEBURST类型...某物.尝试 C.uchar(CRYPT_BLURBURST)
也没有任何改变.
At this point I'm assuming I'm just not calling the function with the correct arguments. I was under the impression that cdata is of type *C.struct_CRYPT_SETUP
, key should be *byte
(though it doesn't work without the & either) and C.CRYPT_BLUEBURST of type...something. Trying C.uchar(CRYPT_BLURBURST)
also doesn't change anything.
有什么建议可以编译此代码?
Any suggestions on getting this code to compile?
忘记了平台,我正在运行Mac OS X 10.10
Forgot my platform, I'm running Mac OS X 10.10
Edit2(已解决):Jsor关于使用unsafe.Pointer和key的第一个元素的地址的观点有所帮助,但我还必须将C源文件移动到与Go文件相同的目录中.使用C.struct_CRYPT_DATA而不是C.CRYPT_DATA会导致另一个类型错误,因此,如果其他任何人遇到这样的错误:
Edit2 (SOLVED): Jsor's point about using unsafe.Pointer with the address of the first element of key helped but I also had to move my C source files into the same directory as my Go file. There was another type error resulting from using C.struct_CRYPT_DATA instead of C.CRYPT_DATA, so if anyone else runs into errors like this:
./goserv.go:18: cannot use cdata (type *C.struct_CRYPT_SETUP) as type *C.struct___0 in argument to _Cfunc_CRYPT_CreateKeys
然后删除struct_前缀(尽管cgo文档说这就是直接引用C结构类型的方法)
Then remove the struct_ prefix (though the cgo docs say that's how to directly reference C struct types)
推荐答案
You probably want &key[0]
, otherwise you're pointing to the Slice Header, which is a struct of 3 values. You end up getting a pointer to a pointer to your buffer, which is probably not what you want.
通常,指向切片的后备缓冲区的指针是& slice [0]
,而不是& slice
.
In general, the pointer to the backing buffer of a slice is &slice[0]
, not &slice
.
作为标准免责声明:请注意将Go分配的缓冲区传递给C.几乎每个人都这样做(包括我在内),但它
As a standard disclaimer: be warned about passing Go-allocated buffers into C. Almost everybody does it, (including me) but it may not be a good idea, and may stop being supported at some point. It's probably fine as long as you keep a reference to the data for the entire duration it's in C, and don't store the pointer for later use on the C side, but it's plausible you'll end up with weirdness due to the Go 1.3 stack moving GC.
更新:我刚刚记得的东西-C语言中的 void *
类似于Go的 unsafe.Pointer
.所以您的电话应该是:
Update: Something I just remembered -- void*
in C is analogous to Go's unsafe.Pointer
. So your call should be:
C.CRYPT_CreateKeys(cdata, unsafe.Pointer(&key[0]), C.CRYPT_BLUEBURST)
另一个问题可能是,如果您通常将外部库与 -l </code>链接.为此,请使用
Another issue may be if you usually link an external library with -l
. For this, use
// #cgo LDFLAGS: -llibname
在导入"C"
上方的区域中进行添加.
In the area right above import "C"
where you do your includes.
Edit2:另外,从更多的角度看,它看起来好像没有在头文件中定义函数 CRYPT_CreateKeys
-仅是函数原型.确保是否在单独的.c文件中定义了该文件,以将其声明为 extern
.否则,将跳到Go.
Also, looking at it more, it looks like the function CRYPT_CreateKeys
is not defined in the header file -- only the function prototype. Make sure if it's defined in a separate .c file to declare it extern
. Not doing so will trip up Go.
这篇关于正确的Go类型传递给C函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!