Golang中CGO回调函数传递C字符串指针的实现方法

Golang中CGO回调函数传递C字符串指针的实现方法

// 初始化 C 字符串
str := C.Cstring("foo")

// 调用带有回调函数 callback(void *) 和 str 的 C 函数
C.cfun(str, C.callback) // cfun(void *data)

// C.callback 调用 goCallback
callback(void * data){
    // 此时可以获取到 str,但在 goCallback() 函数内部却不行。
    goCallback(data);
}

可能的原因是什么?

2 回复

你必须在Go回调函数中调用C.GoStringC.GoStringN来转换为Go的string类型。引自cgo命令 - cmd/cgo - pkg.go.dev

// C string to Go string
func C.GoString(*C.char) string

// C data with explicit length to Go string
func C.GoStringN(*C.char, C.int) string

更多关于Golang中CGO回调函数传递C字符串指针的实现方法的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在CGO回调函数中传递C字符串指针时,需要确保Go回调函数接收正确的参数类型。问题在于Go回调函数没有正确声明接收C字符串指针的类型。以下是正确的实现方法:

package main

/*
#include <stdlib.h>
#include <string.h>

typedef void (*callback_t)(void*);

void cfun(void* data, callback_t cb) {
    cb(data);
}

static void c_callback(void* data) {
    // C端的回调函数
}
*/
import "C"
import (
    "fmt"
    "unsafe"
)

//export goCallback
func goCallback(data unsafe.Pointer) {
    // 将C字符串指针转换为Go字符串
    str := C.GoString((*C.char)(data))
    fmt.Printf("Received string: %s\n", str)
}

func main() {
    // 初始化C字符串
    str := C.CString("foo")
    defer C.free(unsafe.Pointer(str)) // 确保释放内存
    
    // 调用C函数,传递字符串指针和回调函数
    C.cfun(unsafe.Pointer(str), C.callback_t(C.c_callback))
}

需要创建C端的包装函数:

// 在C代码部分添加
static void c_callback(void* data) {
    void goCallback(void*);
    goCallback(data);
}

或者使用更直接的方式:

package main

/*
#include <stdlib.h>

typedef void (*callback_t)(char*);

void cfun(char* data, callback_t cb) {
    cb(data);
}
*/
import "C"
import (
    "fmt"
    "unsafe"
)

//export goCallback
func goCallback(data *C.char) {
    str := C.GoString(data)
    fmt.Printf("Received string: %s\n", str)
}

func main() {
    str := C.CString("foo")
    defer C.free(unsafe.Pointer(str))
    
    // 直接传递Go回调函数给C
    C.cfun(str, C.callback_t(C.goCallback))
}

关键点:

  1. Go回调函数需要使用//export指令导出
  2. 参数类型需要正确匹配:unsafe.Pointer或具体的C类型(如*C.char
  3. C字符串需要使用C.CString创建,并用C.free释放
  4. 回调函数类型需要在C端正确定义

如果仍然无法在goCallback中获取字符串,检查C函数的回调签名是否与Go函数匹配,并确保内存管理正确。

回到顶部