我正在尝试调用C ++函数:
void TestFunc(void(*f)(void)) { f(); }
来自Go Code。
我真的希望它只是将Go函数传递给该函数。我知道我可以将它包装成一个类,并使用%feature(“director”)来解决它,但在我的情况下,这不是最佳解决方案。
从我在this page中看到的,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部分看起来“干净”。
谢谢。
答案 0 :(得分:5)
成功!我有一个有效的解决方案:
我所做的想法是用“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->运行(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代码就像它一样,并且它有效:)