【问题标题】:How to call C function received as an argument如何调用作为参数接收的 C 函数
【发布时间】:2019-08-31 06:21:34
【问题描述】:

我想使用经过 C 语言调整的 Go 库。 我制作了 GoAdder Go 函数,它有 3 个参数 int x、y 和函数类型为 f。

GoAdder 函数将调用 f 参数。

adder.go

package main

import "fmt"

import "C" 

//export Ftest
type Ftest func(C.int);

//export GoAdder
func GoAdder(x, y int, f Ftest) int {
    fmt.Printf("Go says: adding %v and %v\n", x, y) 
    f(10); 

    return x + y
}

func main() {} // Required but ignored

我将 go 包构建为上面名为 libadder.a 的静态库,如下所示:

go build -buildmode=c-archive -o libadder.a adder.go

然后我在下面编写了 C++ 代码。

ma​​in.c

#include <stdio.h>
#include "adder/libadder.h"

void a( GoInt a ){
  printf("Hello %d", a);
}

int main() {
  printf("C says: about to call Go...\n");
  int total = GoAdder(1, 7, &a);
  printf("C says: Go calculated our total as %i\n", total);
  return 0;
}

我已经像这样编译了来源:

gcc -pthread -o static_go_lib main.c adder/libadder.a

执行上面的代码时会发生错误

unexpected fault address 0x0
fatal error: fault
[signal SIGSEGV: segmentation violation code=0x80 addr=0x0 pc=0x563c99b74244]

goroutine 17 [running, locked to thread]:
...

如何在go函数GoAdder中获取正确的C函数地址a

我引用了https://github.com/draffensperger/go-interlang/tree/master/c_to_go/static_go_lib

【问题讨论】:

  • @TedLyngmo 我用过这个go build -buildmode=c-archive -o libadder.a
  • 好的,我已将其添加到问题中,但您可以使用edit 链接自行修改/编辑您的问题。
  • 不客气,但我仍然没有足够的信息来自己重现该问题。 adder/libadder.h 变为 libadder.h 但即使在您的 .cpp 文件中进行了更改,编译也会失败:命令:g++ useadder.cpp -o useadder -L. -ladder -lpthread 给出:error: invalid conversion from ‘void (*)(GoInt)’ {aka ‘void (*)(long long int)’} to ‘void*’。您需要提供更多信息和/或更正该错误。
  • 我正在尝试帮助您更新实际问题,使其独立,以便知道这些东西的人(我不知道)会产生兴趣并提供帮助。一个好问题不需要人们从任何地方下载项目。把需要的东西放在问题中。创建一个minimal reproducible example,做 C/Go 的人更有可能会跳起来。
  • @TedLyngmo 好的,我已经理解你的希望和你想要的方向。对不起。我希望这个问题得到更快的解决。但我做错了。谢谢您的帮助。我会用更多信息更新我的问题。

标签: c go cross-language


【解决方案1】:

C 函数只是跳转指针,而 golang 的回调是复杂的结构体,不能转换。 只有一种(安全的)方法可以调用 C 函数指针: 1)在某处声明:

//go:linkname cgocall runtime.cgocall
//go:nosplit
func cgocall(fn, arg unsafe.Pointer /* may be uintptr */) int32

2) 另外,请注意类型安全:

func GoAdder(x, y C.int, f unsafe.Pointer /*  don't sure if this available, mb C.uintptr_t */) C.int

3) C 函数应该将指针(指向什么)作为参数

void a(GoInt *a)

(我会使用原生类型)

4)

ten := 10
cgocall(f, unsafe.Pointer(&ten))

(如果你想传递几个参数,它应该是结构)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-12
    • 2019-02-19
    • 1970-01-01
    相关资源
    最近更新 更多