Search code examples
c++arraysgowrappercgo

Exchange data structures (arrays) between Go (golang) and C++


I'm trying to connect a C++ library to an appserver written in Go. The goal is that both the C++ library and the appserver are working on a common data structure, which means that:

  1. The Go appserver can access an array created by the C++ library.
  2. The C++ library can work on an array created by the Go appserver.

I was playing a little bit around with cgo and connecting C++ and everything worked so far... However, when it comes to exchanging pointers to data structures I'm lost. What I tried so far:

//c++ library header: xyz.h

#include <stdlib.h>

class CppLib {
 public:
  CppLib(unsigned int input);

  int * CreateArray();
};

//C++ library implementation: xyz.cpp
#include "xyz.h"

CppLib::CppLib(unsigned int input) {
    _input = input;
  }

int * CppLib::CreateArray() {
    int values = 5;
    int * myPointer = new int [values];
    for (unsigned i = 0; i < values; ++i) {
        myPointer[i] = i;
    }
    return myPointer;
}

The interface implementation looks like:

//interface.h

int * CCreateArray();

//interface.cc
#include "../lib/xyz.h"

extern "C" {

  int * CCreateArray() {
    CppLib lib(1);
    return lib.CreateArray();
  }
}

Finally the go implementation looks like:

package cgo_lib

// #cgo CFLAGS: -I../lib
// #cgo LDFLAGS: -L../lib -linterfacelib
// #include "interface.h"
import "C"

func GoCreateArray() *int {
    return *int(C.CCreateArray())
}

When compiling I receive the following error:

# cgo_lib
../cgo_lib/cgo_lib.go:13: cannot convert _Cfunc_CCreateArray() (type *C.int) to type int
../cgo_lib/cgo_lib.go:13: invalid indirect of int(_Cfunc_CCreateArray()) (type int)

So my question is: How to exchange pointers to data structures between C++ and Go. Above I just described the way from C++ to GO, but I'm also interested in the other way round.

Thanks a lot for your help in advance.


Solution

  • This here:

    return *int(C.CCreateArray())
    

    can be written as

    return *((int)(C.CCreateArray()))
    

    You're derreferencing an int, which results in:

    invalid indirect of int(_Cfunc_CCreateArray()) (type int)
    

    And inside that statement, observing only this part:

    (int)(C.CCreateArray())
    

    You're trying to convert an *C.int to an int, which won't work cause the first is a pointer and the second not.

    Beyond that and the memory-management trouble that @tadman mentions in the comments of your question, Go does not represent arrays as pointers to their first element as C does.

    If you want to share ints you'll have to be specific about their width: an int in Go has an arch-dependent width, as well as a C int.

    Read more about CGO: http://golang.org/cmd/cgo/

    Once you have fixed all these problems, you'll have to proceed something like this:

    s := make([]int32, 0, 0)
    
    h := (*reflect.SliceHeader)((unsafe.Pointer)(&s))
    
    h.Data, h.Len, h.Cap = P, L, L // see below
    
    s = *(*[]int32)(h)
    

    where P is a Go uintptr to your array, which you created in C++ and L is the length of the array as a Go int