我正在将我在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结构类型)
答案 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。