0

I have a C++ program that uses some go code compiled to a c library through cgo. I'd like to provide some C delegates / function pointers to the cgo library so that the go code can invoke some code provided by my C++ program. I find many examples how to call go functions from within C++ but nothing vice versa.

My go package looks like this

package main

import (
    "fmt"
    "unsafe"
)

/*
    #include <stdlib.h>
    typedef char* (*Callback)(char* args);
*/
import "C"

//export RegisterCallback
func RegisterCallback(funcptr unsafe.Pointer) {
    cstr := C.CString("hello from go")
    defer C.free(unsafe.Pointer(cstr))

    foo := *(*func(*C.char) *C.char)(funcptr)
    result := foo(cstr)

    fmt.Println(C.GoString((*C.char)(result)))
}

func main() {
}

and I am calling it from C++ like this

char* foo(char* args)
{
    std::cout << args;
    return "hello from C++";
}

//...
RegisterCallback((void*) &foo);

This, however, crashes badly within go.

Sc4v
  • 348
  • 2
  • 10
  • 1
    C++ calling conventions are often tricky. To call a C++ function from Go, mark it as a C function (`extern C`) and add any special linkage requirements that your C++ compiler might require for this as well. Then you'll be calling a C function from Go, which is supported. Do not try to call it through a pointer. If you need to do that, export a C function wrapper that calls through a pointer. – torek Nov 22 '20 at 00:55
  • I have the particular requirement to pass a function pointer, unfortunately. So I’d go through a C function, possibly with a payload. I am struggling how to pass that c function pointer to my go library and then, how to call it from go – Sc4v Nov 22 '20 at 08:05
  • C++ can always call C (and vice versa) using POD (https://stackoverflow.com/questions/146452/what-are-pod-types-in-c), and via cgo, you can call C from Go or vice versa, so that's the adaptation scheme. – torek Nov 22 '20 at 08:31
  • great, to my understanding that's what I am doing by passing a pointer. Looking at my code in the question, can you spot anything that is obviously wrong? Appreciate it! – Sc4v Nov 22 '20 at 08:38
  • 1
    You're taking a *function pointer* (`&foo`) and converting it to a *data pointer* (`void *`). The only guarantee you get is that you can call a *C function* (not C++ function) *by name*, so that's what you have to do: `CallC(args)`. That function, written in plain C (not C++), can take the arguments and use them to pick which C++ function to call in whatever way your C and C++ code are allowed to cooperate by your compilation system. – torek Nov 22 '20 at 23:32
  • Consider, e.g., having a table of pointer-to-C++-function in your C code: `cppfunc table[MAX_REGISTERED]` for instance. Then your C function consists, in its entirety, of `char *CallC(int arg) { return table[arg](); }`. (Add more arguments as desired, but note that the argument is now just an index into the table, which lives in the C/C++ interface.) – torek Nov 22 '20 at 23:35

0 Answers0