[英]Calling a Go callback function from C++ through SWIG
我正在尝试调用C ++函数:
void TestFunc(void(*f)(void)) { f(); }
来自Go Code。
我真的希望它只是将Go函数传递给该函数。 我知道我可以将它包装到一个类中,并使用%feature(“director”)解决它,但这不是我案例中的最佳解决方案。
从我在本页中看到的,Go中的函数指针应该与C ++中的相同,所以我尝试了以下.swig文件:
%{
#include "test.h"
%}
%typemap(gotype) FUNC* "func()"
%typemap(in) FUNC* {
$1 = (void(*)(void))$input;
}
%apply FUNC* { void(*)(void) };
%include "test.h"
我很安静地感到惊讶,它起初工作,但后来注意到它并不总是有效:(。
例如,在此Go代码中,它按预期工作:
import "fmt"
import "test_wrap"
func main() {
b := false
test_wrap.TestFunc(func() { b = true })
fmt.Println(b) // This actually DOES print "true"!
}
但在其他情况下,它不起作用。 例如,这里:
import "fmt"
import "test_wrap"
func main() {
test_wrap.TestFunc(func() { fmt.Println("SUCCESS") })
fmt.Println("Done")
}
我真的得到:
SUCCESS
SIGILL: illegal instruction
PC=0x4c20005d000
goroutine 1 [syscall]:
test_wrap._swig_wrap_TestFunc(0x400cb0, 0x400c2a)
base_go_test__wrap_gc.c:33 +0x32
test_wrap.TestFunc(0x400cb0, 0x2)
base_go_test__wrap.go:37 +0x25
main.main()
test.go:8 +0x2a
goroutine 2 [syscall]:
created by runtime.main
go/gc/src/pkg/runtime/proc.c:225
rax 0x0
rbx 0x0
rcx 0x0
rdx 0x8
rdi 0x4c200073050
rsi 0x4c20004c0f0
rbp 0x0
rsp 0x4c20004c100
r8 0x2
r9 0x4b0ae0
r10 0x4f5620
r11 0x4dbb88
r12 0x4f5530
r13 0x7fad5977f9c0
r14 0x0
r15 0x3
rip 0x4c20005d000
rflags 0x10202
cs 0x33
fs 0x0
gs 0x0
请注意它确实打印了“SUCCESS”,这意味着函数DID运行,即使我将更复杂(和长)的代码放入此函数中,它确实执行完美,但它没有回来:(。
请让我知道你的想法,以及我如何解决这个问题。 我不介意在C ++部分添加一些代码,但我真的希望Go部分看起来“干净”。
谢谢。
成功! 我有一个有效的解决方案:
我所做的是用“director”包装回调,并将Go函数指针“返回”Go,这样就可以在该上下文中运行。
下面的解决方案并不完美,但它足够接近我的需求,从现在开始很容易让它变得完美。
C ++文件:
class Callback {
public:
virtual void Run(void(*f)(void)) = 0;
virtual ~Callback() {}
};
Callback* GlobalCallback;
void TestFunc(void(*f)(void)) {
GlobalCallback->Run(f);
}
我添加了一个Callback类,它将在Go中“扩展”(使用Swig director),我将拥有这个扩展类的全局实例。 因此,调用该实例的Run()将调用Go函数,该函数将接收函数指针。
请注意我的TestFunc现在而不是仅运行f(),通过GlobalCallback运行它。 通过添加另一个返回指向运行GlobalCallback-> Run(f)的函数的指针的函数很容易修复,并将此指针传递给函数而不是* f。
我的Swig文件:
%{
#include "test.h"
%}
%module(directors="1") Callback
%feature("director");
%typemap(gotype) FUNC* "func()"
%typemap(in) FUNC* {
$1 = (void(*)(void))$input;
}
%apply FUNC* { void(*)(void) };
%include "test.h"
%insert(go_wrapper) %{
type go_callback struct { }
func (c* go_callback) Run(f func()) {
f()
}
func init() {
SetGlobalCallback(NewDirectorCallback(&go_callback{}))
}
%}
请注意,我添加了一个init()函数,该函数使用运行指针的Go函数设置GlobalCallback。
就是这样,Go代码就是这样,它的工作原理:)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.