1

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.

8
  • You can't return a pointer to an item allocated on the stack. This is completely invalid. CreateArray needs to specifically allocate that array using new. Commented Feb 17, 2015 at 16:34
  • Hi tadman, thanks for the comment. Yes thats true... thanks for pointing that out. But even using new the core issue of the question remains, because also the errors are still there. Commented Feb 17, 2015 at 16:43
  • Does casting with (*int)(C.CCreateArray()) work better? Not as familiar with Go. I think you're inadvertently casting to int and then trying to de-reference that somehow. I'd also try skipping the explicit cast and seeing if Go can infer that. Commented Feb 17, 2015 at 16:47
  • Unfortunately not. I still receive: cannot convert _Cfunc_CCreateArray() (type *C.int) to type *int Commented Feb 17, 2015 at 16:49
  • 1
    Thanks for pointing this out tadman. In this case the best option would be to create an own free method that releases the memory using delete []. Commented Feb 17, 2015 at 20:47

1 Answer 1

1

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

Sign up to request clarification or add additional context in comments.

3 Comments

Hi thwd, thanks for the answer. I could make it work exactly as suggested in your post as well as in the source you were linking. The only question that remains is: When using the method above, one receives an array of C.int values. Would it be advisable to convert them to the respective go uint?
Yes, make them Go types, regardless if signed or unsigned. If you don't then you'll have to import "C" all over your Go code.
Just two minor corrections: The second line should look like -- h := *(*reflect.SliceHeader)((unsafe.Pointer)(&s)) -- and the forth line should be -- s = *(*[]int32)(unsafe.Pointer(&h))

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.