正确的Go类型传递给C函数?

时间:2014-11-06 05:05:41

标签: go cgo

我正在将我在C中编写的一些服务器代码移植到Go,它使用的加密库我 真的不想重写。相反,我正在尝试使用Cgo编写一个包装器,以便我的其余代码可以更轻松地调用它。这是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);

这是我试图开始工作的概念验证片段:

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常量({{1} })但是当我尝试运行 go install goserv 时出现以下错误:

C.CRYPT_BBCFG

此时我假设我不是用正确的参数调用函数。我的印象是cdata的类型为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 ,密钥应该是*C.struct_CRYPT_SETUP(虽然没有&或者它不起作用)和C.CRYPT_BLUEBURST类型的东西。尝试*byte也不会改变任何内容。

有关获取此代码进行编译的任何建议吗?

编辑:忘记我的平台,我正在运行Mac OS X 10.10

Edit2(已解决):Jsor关于将unsafe.Pointer与key的第一个元素的地址一起使用的观点有所帮助,但我还必须将我的C源文件移动到与Go文件相同的目录中。使用C.struct_CRYPT_DATA而不是C.CRYPT_DATA导致了另一个类型错误,所以如果其他人遇到这样的错误:

C.uchar(CRYPT_BLURBURST)

然后删除struct_前缀(尽管cgo文档说这是如何直接引用C结构类型)

2 个答案:

答案 0 :(得分:2)

您可能需要&key[0],否则您指向Slice Header,这是3个值的结构。你最终得到一个指向缓冲区指针的指针,这可能不是你想要的。

通常,指向切片后备缓冲区的指针为&slice[0],而不是&slice

作为标准免责声明:请注意将Go分配的缓冲区传递给C.几乎每个人都这样做,(包括我),但may not be a good idea, and may stop being supported at some point。只要您在C中保留对数据的整个持续时间,就可以可能罚款,并且不要存储指针以供日后使用。 C方面,但由于Go 1.3堆栈移动GC,你最终会变得怪异。

更新:我记得的一些事情--C中的void*类似于Go unsafe.Pointer。所以你的电话应该是:

C.CRYPT_CreateKeys(cdata, unsafe.Pointer(&key[0]), C.CRYPT_BLUEBURST)

如果您经常使用-l链接外部库,则可能是另一个问题。为此,请使用

// #cgo LDFLAGS: -llibname

import "C"上方的区域中,您可以在其中进行包含。

Edit2:另外,看一下它,看起来函数CRYPT_CreateKeys没有在头文件中定义 - 只有函数原型。确保它是否在单独的.c文件中定义,以声明它extern。不这样做绊倒Go。

答案 1 :(得分:0)

如果要在两次之间传递缓冲区,则需要再加一点 和C。以这种方式编写C代码是一个不错的选择, 它复制GO本地传递的缓冲区。 当您将缓冲区类型转换为 Int *或其他一些指针类型。 这样,您将独立于提供的缓冲区 通过Cgo。