能否用Go创建含回调函数的C共享库?程序崩溃问题求助
Go创建带回调的C共享库问题解决方案
可以用Go创建包含回调函数的C共享库,但你的代码因跨语言回调类型不匹配和调用传递方式错误导致崩溃,以下是问题分析和修正方案:
问题根源
- 回调类型不兼容:DLL中直接用Go的
func(*C.char)接收回调,而从Loader传递的是C风格函数指针,两者内存布局和调用机制不同,直接调用会触发无效内存访问(报错地址0xffffffffffffffff就是典型的无效指针访问)。 - 指针传递错误:Loader中直接将
C.HelloTo转为uintptr传递,没有按照C函数指针的要求进行正确转换,导致DLL拿到的指针无效。
修正后的代码
1. 共享库(test.dll)代码
package main /* // 定义C标准的回调函数类型 typedef void (*HelloCallback)(char*); */ import "C" import "unsafe" func main() {} //export CALL_BACK func CALL_BACK(f C.HelloCallback) { str := C.CString("FDUTCH") defer C.free(unsafe.Pointer(str)) // 必须释放C字符串,避免内存泄漏 f(str) }
2. 加载程序(loader.exe)代码
package main import ( "fmt" "log" "syscall" "unsafe" ) /* typedef void (*HelloCallback)(char*); void HelloTo(char* name); */ import "C" //export HelloTo func HelloTo(name *C.char) { fmt.Printf("Hello To : %s !!!\n", C.GoString(name)) } func main() { dll, err := syscall.LoadDLL("test.dll") if err != nil { log.Fatalln(err) } defer dll.Release() // 退出前释放DLL资源 proc, err := dll.FindProc("CALL_BACK") if err != nil { log.Fatalln(err) } // 将Go导出函数转为C标准回调指针 callback := C.HelloCallback(C.HelloTo) _, _, errno := proc.Call(uintptr(unsafe.Pointer(&callback))) if errno != 0 { log.Fatalln("CALL_BACK调用失败:", errno) } }
关键注意事项
- 必须用C风格回调类型:在cgo的注释块中定义
typedef,让Go和C双方都识别统一的回调指针格式,不能直接用Go原生函数类型跨语言传递。 - 内存管理:
C.CString分配的内存属于C堆,必须用C.free手动释放,否则会造成内存泄漏。 - 指针转换规范:传递回调指针时,需要用
unsafe.Pointer做类型转换,确保符合C语言的指针传递规则。
内容的提问来源于stack exchange,提问作者FDUTCH
相关产品推荐
相关产品推荐

