通过SWIG从C ++调用Go回调函数

我正在尝试调用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部分看起来“干净”。


慕勒3428872
浏览 275回答 1
1回答

翻翻过去那场雪

成功!我有一个可行的解决方案:我所做的想法是用“ 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导演),并且我将拥有该扩展类的全局实例。因此,调用该实例的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代码保持原样,并且可以正常工作:)
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go