Golang中CGO如何处理void*指针
Golang中CGO如何处理void*指针 我有一个这样的C结构体:
typedef struct {
void* data;
} foo;
我想使用CGO将其复制到等效的Go结构体
type foo struct {
data unsafe.Pointer
}
但我遇到了panic:运行时错误:cgo参数包含指向未固定的Go指针的Go指针 我该怎么办?
4 回复
在将其传递给C之前,你是如何设置data字段的?
更多关于Golang中CGO如何处理void*指针的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
好的,pinner 中的 bug 将在下一个 Go 版本中修复。
此外,当我尝试使用 runtime.Pinner 固定 data 时,它提示 data 不是 Go 指针…
func main() {
fmt.Println("hello world")
}
在CGO中处理void*指针时,遇到"未固定的Go指针"错误通常是因为Go的垃圾收集器移动了指针位置。你需要使用runtime.Pinner来固定指针,或者使用C.malloc分配C内存。以下是解决方案:
方法1:使用runtime.Pinner固定Go指针
package main
/*
#include <stdlib.h>
typedef struct {
void* data;
} foo;
*/
import "C"
import (
"runtime"
"unsafe"
)
type Foo struct {
data unsafe.Pointer
}
func main() {
// 创建Go数据
goData := []byte("Hello from Go")
// 使用Pinner固定Go指针
var pinner runtime.Pinner
pinner.Pin(&goData[0])
// 创建C结构体
cFoo := C.foo{
data: unsafe.Pointer(&goData[0]),
}
// 转换为Go结构体
goFoo := Foo{
data: unsafe.Pointer(cFoo.data),
}
// 使用数据...
_ = goFoo
// 确保在不再需要时解除固定
pinner.Unpin()
}
方法2:使用C.malloc分配C内存
package main
/*
#include <stdlib.h>
#include <string.h>
typedef struct {
void* data;
} foo;
*/
import "C"
import (
"unsafe"
)
type Foo struct {
data unsafe.Pointer
}
func main() {
// Go数据
goData := []byte("Hello from Go")
// 使用C.malloc分配内存并复制数据
cData := C.malloc(C.size_t(len(goData)))
defer C.free(cData)
C.memcpy(cData, unsafe.Pointer(&goData[0]), C.size_t(len(goData)))
// 创建C结构体
cFoo := C.foo{
data: cData,
}
// 转换为Go结构体
goFoo := Foo{
data: unsafe.Pointer(cFoo.data),
}
// 访问数据
// 注意:需要将unsafe.Pointer转换为正确的类型
data := C.GoBytes(goFoo.data, C.int(len(goData)))
_ = data
}
方法3:处理复杂场景的完整示例
package main
/*
#include <stdlib.h>
#include <string.h>
typedef struct {
void* data;
int size;
} buffer;
buffer* create_buffer(void* data, int size) {
buffer* buf = (buffer*)malloc(sizeof(buffer));
buf->data = malloc(size);
memcpy(buf->data, data, size);
buf->size = size;
return buf;
}
void free_buffer(buffer* buf) {
if (buf) {
free(buf->data);
free(buf);
}
}
*/
import "C"
import (
"fmt"
"unsafe"
)
type Buffer struct {
data unsafe.Pointer
size int
}
func main() {
// 准备数据
goData := []byte("Hello, CGO!")
// 创建C缓冲区
cBuf := C.create_buffer(
unsafe.Pointer(&goData[0]),
C.int(len(goData)),
)
defer C.free_buffer(cBuf)
// 转换为Go结构体
goBuf := Buffer{
data: unsafe.Pointer(cBuf.data),
size: int(cBuf.size),
}
// 安全访问数据
dataSlice := (*[1 << 30]byte)(goBuf.data)[:goBuf.size:goBuf.size]
fmt.Printf("Data: %s\n", string(dataSlice))
// 或者使用C.GoBytes
goBytes := C.GoBytes(goBuf.data, C.int(goBuf.size))
fmt.Printf("GoBytes: %s\n", string(goBytes))
}
关键注意事项:
- 不要直接传递Go指针到C,除非使用
runtime.Pinner固定 - 使用
C.malloc分配的内存由C管理,不受Go GC影响 - 使用
C.GoBytes可以安全地将C数据复制到Go切片 - 确保释放C分配的内存,使用
defer C.free() - 在Go 1.21+中推荐使用
runtime.Pinner,它比旧的runtime.KeepAlive更安全
选择哪种方法取决于你的具体需求:如果数据主要在Go端使用,使用方法1;如果需要在C端长期持有数据,使用方法2。

