2012-12-22 108 views
4

調用從C++圍棋回調函數,我想調用C++函數:通過痛飲

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

從運行的代碼。

我真的希望它是,我只是傳遞一個Go功能的功能。我知道我可以將它封裝到一個類中,並使用%特性(「導演」)來解決它,但這不是我的最佳解決方案。

從我在this page看到,指針在運轉功能,應該是相同的,如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"! 
} 

但在其他情況下,它不會w ^掃。例如,在這裏:

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 

請注意,它並打印「成功」,這意味着該函數是走,即使我把更復雜的(和長)代碼到這個功能,它確實執行,但它沒有回來:(

請讓我知道你在想什麼,我怎麼能解決這個問題 我不介意添加一些代碼在C++部分,但我真的希望Go部分看起來「乾淨」。

謝謝。

回答

4

成功!我有一個解決方案:

我做了什麼的想法是用「導演」包裝回調,並將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「擴展」,我也會有這樣的擴展類的全局實例。因此,調用該實例的Run()將調用Go函數,該函數將接收函數指針。

請注意,我的TestFunc現在不是隻運行f(),而是通過GlobalCallback運行它。通過添加另一個函數來返回一個指向運行GlobalCallback-> Run(f)的函數的指針,並將該指針傳遞給函數而不是* f,這很容易解決。

我痛飲文件:

%{ 
#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{}))                          
} 
%} 

注意,我添加了設置GlobalCallback與運行的指針轉到功能的init()函數。

就是這樣,Go代碼就像它一樣,它的工作原理:)