在Go(golang)和C++之间交换数据结构(数组),

huangapple go评论104阅读模式
英文:

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

问题

我正在尝试将一个C++库连接到一个用Go编写的应用服务器。目标是让C++库和应用服务器都能够使用共同的数据结构,也就是说:

  1. Go应用服务器可以访问由C++库创建的数组。
  2. C++库可以处理由Go应用服务器创建的数组。

我已经使用cgo进行了一些尝试,并且在连接C++方面一切都正常... 但是,当涉及到交换数据结构的指针时,我有些迷茫。我目前尝试的方法如下:

// C++库头文件: xyz.h

#include <stdlib.h>

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

int * CreateArray();
};

// C++库实现文件: 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;
}

接口实现如下:

// interface.h

int * CCreateArray();

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

extern "C" {

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

最后,Go实现如下:

package cgo_lib

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

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

在编译时,我收到以下错误:

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)

所以我的问题是:如何在C++和Go之间交换数据结构的指针。上面我只描述了从C++到Go的方式,但我也对另一种方式感兴趣。

非常感谢您的帮助。

英文:

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 &lt;stdlib.h&gt;

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

  int * CreateArray();
};

//C++ library implementation: xyz.cpp
#include &quot;xyz.h&quot;

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

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

The interface implementation looks like:

//interface.h

int * CCreateArray();

//interface.cc
#include &quot;../lib/xyz.h&quot;

extern &quot;C&quot; {
      
  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 &quot;interface.h&quot;
import &quot;C&quot;

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.

答案1

得分: 1

这里:

return *int(C.CCreateArray())

可以写成:

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

你正在解引用一个 int,结果是:

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

在这个语句中,只观察这部分:

(int)(C.CCreateArray())

你试图将 *C.int 转换为 int,但这是行不通的,因为第一个是指针,而第二个不是。

除此之外,在你的问题的评论中,@tadman提到了内存管理的问题,Go 不像 C 一样将数组表示为指向它们的第一个元素的指针。

如果你想共享 int,你需要明确它们的宽度:Go 中的 int 有一个与体系结构相关的宽度,与 C 中的 int 不同。

了解更多关于 CGO 的信息:http://golang.org/cmd/cgo/

一旦你解决了所有这些问题,你需要按照以下步骤进行操作:

s := make([]int32, 0, 0)

h := (*reflect.SliceHeader)((unsafe.Pointer)(&s))

h.Data, h.Len, h.Cap = P, L, L // 请参考下面的说明

s = *(*[]int32)(h)

其中 P 是一个指向你在 C++ 中创建的数组的 Go uintptr,而 L 是数组的长度,类型为 Go 的 int

英文:

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)(&amp;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

huangapple
  • 本文由 发表于 2015年2月18日 00:31:43
  • 转载请务必保留本文链接:https://go.coder-hub.com/28566242.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定