Jump to Navigation

golang CGO FAQ & TIPS : cgo 从 C 传递 slice 到 go

cgo 从 C 传递 slice 到 go

这里一般会用在c的callback中。

需要加一个wrapper,比直接调用go函数中间多了一个转换步骤,但方便了许多。

执行流程为,c调用发起 -> c wrapper -> go export

.go:

//export a_function_callback
 func a_function_callback(args []C.astruct) {}

.c:

extern void a_function_callback(GoSlice args);

void a_function_callback_c(args *C.astruct) {
    GoSlice args_go;
    args_go.data = args;
    args_go.len = nargs;
    args_go.cap = nargs;
    return a_function_callback(args_go);
}

这里的GoSlice需要从 export 出来的 .h 中获取,或者 include 该 .h文件。 也可以直接拷贝过来,注意不要产生类型冲突。

#ifndef GO_CGO_PROLOGUE_H
#define GO_CGO_PROLOGUE_H

 typedef long long GoInt64;
 typedef GoInt64 GoInt;
 typedef struct { void *data; GoInt len; GoInt cap; } GoSlice;

 #endif

C.CString 的自动化回收方法

一般使用 C.CString 时,定义一个临时变量存储结果,使用 defer C.free 回收这个临时的变量。

在 go 的 runtime 包中,有一个SetFinalizer方法,可以在回收对象的时候调用一个处理函数。

那么我们可以考虑使用它来自动化回收 C.CString产生的临时变量。

       type CString struct {
             Ptr *C.char
       }

       func CCString(s string) *CString {
            p := C.CString(s)
             this := &CString{Ptr: p}

            runtime.SetFinalizer(this, freeCString)
             return this
       }

       func freeCString(cs *CString) {
              C.free(unsafe.Pointer(cs.Ptr))
       }

在使用的时候,基本能嵌入到调用的位置,不需要显式定义一个临时变量并执行 defer C.free。

       C.somefunc(CCString(s).Ptr)

注意,只在somefunc不接管传递的参数的所有权时调用这种方式,如果somefunc接管了所有权, 而在未来某时间内存被回收了,则会出现程序SEGFAULT崩溃。

这种可能会产生一点runtime效率损失,另外还有额外的内存分配,看情况使用。

bool 类型的转换处理

在 C 语言中,c99之前 bool 都是定义为 int的,要想转换为go的bool类型,比较曲折。

     var bval_c C.GBoolean
     var bval_go bool
     if int(bval) == 1  { 
           bval_go = true
     } else {
           bval_go = false
     }

如果go有三元运算符的话,也可一行代码实现该转换,问题是go没有三元运算符。

一般来说,对其包装一个简单的转换函数比较好,比如 c2gobool(C.GBoolean).

有时候不同的 C 项目中 bool 定义不同,所以一般需要为每个项目定义这么一个函数,而不能放在一个库中共用。

在 c99 之后,则没有这个问题,cgo能够直接判断是内置的bool类型,能够直接转换为go的bool。

     var bval_c C._Bool
     var bval_go = bool(bval_c)

Add new comment

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
CAPTCHA
This question is for testing whether or not you are a human visitor and to prevent automated spam submissions.
Image CAPTCHA
Enter the characters shown in the image.


Main menu 2

Story | by Dr. Radut