Golang中传递int指针到C函数时发生panic的解决方法

Golang中传递int指针到C函数时发生panic的解决方法 我理解规则Go代码可以将Go指针传递给C,前提是该指针指向的Go内存不包含任何Go指针。但是当我向C函数传递参数时,发生了一些奇怪的情况。

代码示例1和2是该问题的示例代码。

在代码示例1中,我将&f.a传递给C函数,go运行时捕获了cgo参数包含指向Go指针的Go指针错误。我认为f.a中没有Go指针。

在代码示例2中,我将属性a改为指针,代码可以正常运行。

我没有看到示例1和2之间有什么大的区别。为什么代码示例1会出现panic?

// 代码示例1
package main

/*
#include <stdio.h>

void nothing(void *x) {
}
*/
import "C"
import (
        "unsafe"
)

type foo struct {
        p *int
        a int
}

func main() {
        f := &foo{}
        b := 10
        f.p = &b
        f.a = b
        C.nothing(unsafe.Pointer(&f.a))
}

代码示例1的输出:

panic: runtime error: cgo argument has Go pointer to Go pointer

goroutine 1 [running]:
main.main.func1(0xc420010038)
        /root/go/src/github.com/winglq/test/pointer/main.go:23 +0x96
main.main()
        /root/go/src/github.com/winglq/test/pointer/main.go:24 +0x7f
// 代码示例2
package main

/*
#include <stdio.h>

void nothing(void *x) {
}
*/
import "C"
import (
        "unsafe"
)

type foo struct {
        p *int
        a *int
}

func main() {
        f := &foo{}
        b := 10
        f.p = &b
        f.a = &b
        C.nothing(unsafe.Pointer(f.a))
}

更多关于Golang中传递int指针到C函数时发生panic的解决方法的实战教程也可以访问 https://www.itying.com/category-94-b0.html

2 回复

你好,

我无法确切解释原因,但看起来你遇到了 cgo 中的一个典型问题:https://jamesadam.me/2016/03/26/c-and-go-dealing-with-void-parameters-in-cgo/

希望这能有所帮助。

更多关于Golang中传递int指针到C函数时发生panic的解决方法的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


问题出现在代码示例1中,&f.a 实际上创建了一个指向结构体字段的指针,而该结构体本身包含Go指针字段 p。虽然 f.a 是一个整数值,但 &f.a 获取的是结构体 foo 中字段 a 的地址,而整个结构体 f 包含Go指针字段 p。因此,当传递 &f.a 时,Go运行时检测到该指针指向的内存位于包含Go指针的结构体中,违反了cgo规则。

在代码示例2中,f.a 本身就是一个 *int 类型,直接传递 f.a(通过 unsafe.Pointer(f.a))指向的是整数 b 的地址,而 b 是一个整数变量,不包含任何Go指针,因此不会触发panic。

以下是详细解释和修复方法:

在代码示例1中,&f.a 是结构体 foo 中字段 a 的地址。由于结构体 foo 包含字段 p(一个Go指针),整个结构体被视为包含Go指针的内存。因此,传递 &f.a 被视为传递一个指向包含Go指针的内存的指针,违反了cgo规则。

在代码示例2中,f.a 是一个指向整数 b 的指针,直接传递 f.a 不会涉及结构体本身,因为 f.a 指向的是独立的整数内存,不包含Go指针。

要修复代码示例1,避免传递结构体字段的地址,如果必须传递整数指针,可以先将整数值复制到一个独立的变量中,然后传递该变量的地址。例如:

package main

/*
#include <stdio.h>

void nothing(void *x) {
}
*/
import "C"
import (
    "unsafe"
)

type foo struct {
    p *int
    a int
}

func main() {
    f := &foo{}
    b := 10
    f.p = &b
    f.a = b
    // 创建一个独立变量,避免涉及结构体
    temp := f.a
    C.nothing(unsafe.Pointer(&temp))
}

在这个修复版本中,temp 是一个独立的整数变量,不包含任何Go指针,因此传递 &temp 不会触发panic。这确保了传递给C函数的内存不包含Go指针。

总结:当传递指针给C函数时,必须确保指针指向的内存区域完全不包含Go指针,包括间接通过结构体字段的情况。在代码示例1中,&f.a 指向的结构体内存包含Go指针字段 p,因此被Go运行时拒绝。通过提取值到独立变量,可以安全传递。

回到顶部