douxian1939 2014-11-06 05:05
浏览 92
已采纳

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

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)
}

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

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?

Edit: Forgot my platform, I'm running Mac OS X 10.10

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

Then remove the struct_ prefix (though the cgo docs say that's how to directly reference C struct types)

  • 写回答

2条回答 默认 最新

  • duanou1904 2014-11-06 07:03
    关注

    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.

    In general, the pointer to the backing buffer of a slice is &slice[0], not &slice.

    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.

    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)
    

    Another issue may be if you usually link an external library with -l. For this, use

    // #cgo LDFLAGS: -llibname
    

    In the area right above import "C" where you do your includes.

    Edit2: 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.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥20 iOS绕地区网络检测
  • ¥15 python验证码滑块图像识别
  • ¥15 根据背景及设计要求撰写设计报告
  • ¥15 QT6颜色选择对话框显示不完整
  • ¥20 能提供一下思路或者代码吗
  • ¥15 用twincat控制!
  • ¥15 请问一下这个运行结果是怎么来的
  • ¥15 单通道放大电路的工作原理
  • ¥30 YOLO检测微调结果p为1
  • ¥15 DS18B20内部ADC模数转换器