正确的Go类型传递给C函数? [英] Correct Go type to pass to C function?

查看:47
本文介绍了正确的Go类型传递给C函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在将用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)

推荐答案

您可能想要& key [0] ,否则您将指向

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆