Я пытаюсь вызвать функцию C ++:
void TestFunc(void(*f)(void)) { f(); }
Из Go Код.
Я бы очень хотел, чтобы я просто передал функцию Go этой функции. Я знаю, что могу обернуть его в класс и решить с помощью% feature («директор»), но в моем случае это не оптимальное решение.
Из того, что я видел в эта страница, указатели для работы в 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=0x4c20005d000goroutine 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 выглядела «чисто».
Спасибо.
Успех! У меня есть решение, которое работает:
Идея того, что я сделал, заключается в том, чтобы обернуть обратный вызов «директорами» и «вернуть» указатель функции 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 (), которая устанавливает GlobalCallback с функцией Go, которая запускает указатель.
Вот и все, код Go такой, какой был, и он работает 🙂
Других решений пока нет …