我正在用CGO从GO代码编译一个C库,然后从C#调用库函数。
在这段GO代码中,我有一个函数需要一个**[]string输入,例如:func StringArray(strings []string)
我还有另一个函数需要[]int**输入,例如:func IntArray(vals []int)
如果查看生成的头文件,可以看到上述函数的如下内容:
extern __declspec(dllexport) void IntArray(GoSlice vals);
extern __declspec(dllexport) void StringArray(GoSlice strings);
通过创建以下结构,我可以成功地从C#调用IntArray
函数:
internal struct GoSlice
{
public IntPtr data;
public long len, cap;
public GoSlice(IntPtr data, long len, long cap)
{
this.data = data;
this.len = len;
this.cap = cap;
}
}
然后像这样调用函数:
long[] data = { 1, 2, 3, 4, 5, 6 };
IntPtr data_ptr = Marshal.AllocHGlobal(Buffer.ByteLength(data));
Marshal.Copy(data, 0, data_ptr, data.Length);
var nums = new GoSlice(data_ptr, data.Length, data.Length);
IntArray(nums);
Marshal.Copy(nums.data, data, 0, data.Length);
我还可以通过创建以下结构成功地调用期望string输入的函数:
internal struct GoString
{
public string msg;
public long len;
public GoString(string msg, long len)
{
this.msg = msg;
this.len = len;
}
}
然后像这样调用函数:
string inputString = "Test";
GoString goString = new GoString(inputString, inputString.Length);
StringInput(goString);
我努力实现的是将预期的[]字符串GoSlice传递给StringArray
函数。有什么建议吗?我需要GoSlice包含字符串而不是整数。
我尝试过用不同的方法将字符串而不是整数传递给GoSlice,这对混合结果不起作用。我希望最后得到一个[]string GoSlice,它可以在从C#调用“CGO compiled”GO函数时使用。
1条答案
按热度按时间6rqinv9w1#
我有点搞不清楚您在问题中是指
C#
还是Go
类型,但我想我仍然可以为您澄清这一点。首先,
cgo
创建了一个C接口,因此您的问题简化为:看起来你对前者把握得很好,所以我打算把重点放在后者上。
对于具有动态结构的C函数,我们需要知道它的内存大小和布局,因此,一个接受字符串数组(包含与String切片相同类型的数据)的函数在C中看起来可能如下所示
好的,如果我们想在Go语言中使用相同的接口,我们只需要在cgo中匹配它(取自this的另一个答案):
所以现在你可以把上面的函数当作
int Parse22Strings(int argc, char** argv)
来处理,因为这是它被调用的方式。如果你需要返回一个Slice,你只需要把它转换成C类型:对于不透明类型,您可以使用更复杂的方法,但通常情况下,最好的方法是在C结构体中序列化数据并来回传递它。