5

私はC++関数を呼び出そうとしています:

void TestFunc(void(*f)(void)) { f(); }

Goコードから。

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部分を「クリーン」に見せたいと思っています。

ありがとうございました。

4

1 に答える 1

5

成功!私はうまくいく解決策を持っています:

私がやったことのアイデアは、コールバックを「directors」でラップし、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);
}

Goで(Swigディレクターを使用して)「拡張」されるクラスCallbackを追加しました。これにより、この拡張クラスのグローバルインスタンスが作成されます。したがって、そのインスタンスの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{}))                                                                                                     
}
%}

ポインターを実行するGo関数でGlobalCallbackを設定するinit()関数を追加したことに注意してください。

それだけです。Goコードはそのままで、機能します:)

于 2012-12-23T10:02:52.353 に答える