2

我正在将我用 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; }),从我的代码 (via) 调用它也没有问题,C.test()也没有引用任何 #defined'd 常量 ( C.CRYPT_BBCFG),但是当我尝试运行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 是 type *C.struct_CRYPT_SETUP, key 应该是*byte(尽管没有 & 也不能工作)和 C.CRYPT_BLUEBURST 类型......东西。尝试C.uchar(CRYPT_BLURBURST)也不会改变任何事情。

关于编译这段代码有什么建议吗?

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

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

./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 结构类型的方法)

4

2 回答 2

2

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

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

作为标准免责声明:请注意将 Go 分配的缓冲区传递到 C 中。几乎每个人(包括我)都这样做,但这可能不是一个好主意,并且可能会在某个时候停止支持。只要您在 C 中保留对数据的整个持续时间的引用,并且不存储指针以供以后在 C 端使用,这可能就可以了,但是由于 Go 的原因,您最终会感到奇怪1.3 堆栈移动GC。

更新:我刚刚记得的东西——void*在 C 中类似于 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。

于 2014-11-06T07:03:18.237 回答
0

还有一点,如果您在 go 和 C 之间传递缓冲区。以这样的方式编写 C 代码是一个不错的选择,它复制 GO 在本地传递的缓冲区。当您将缓冲区类型转换为 Int* 或其他指针类型时,这将有所帮助。这样,您将独立于 Cgo 提供的缓冲区。

于 2018-08-01T16:20:29.360 回答