从C#调用Golang导出函数时如何处理数组参数

从C#调用Golang导出函数时如何处理数组参数 我正在尝试从C#调用一个Go函数并传入一个数组。然而,我很难让被调用的Go函数将其识别为数组。

在Go中

package main

import “C”

func main() {
}
//export DoInt
func DoInt(dataX []int) int {
return len(dataX)
}

在C#中,我这样导入

[DllImport(@“test.dll”, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
public static extern int DoInt(int[] dataX);

并在一个函数中调用它

  int[] bvals = { 1,  6, 8888, 4343, 3};
  int k = GoFunctions.DoInt(bvals);

在C#中,当我执行代码时,k的值是8888,而在Go函数内部,当我尝试访问dataX[0]时,我无法访问数组元素,并且代码会退出。

我应该传递一个指针吗?还是应该传递数组的引用而不是数组本身?

谢谢


更多关于从C#调用Golang导出函数时如何处理数组参数的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于从C#调用Golang导出函数时如何处理数组参数的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在Go中导出函数给C使用时,数组参数需要特殊处理。Go的切片类型([]int)在C中无法直接识别,需要转换为C兼容的类型。以下是正确的实现方式:

修改Go代码

package main

import "C"
import "unsafe"

//export DoInt
func DoInt(dataX *C.int, length C.int) C.int {
    // 将C数组转换为Go切片
    dataSlice := (*[1 << 30]C.int)(unsafe.Pointer(dataX))[:length:length]
    
    // 如果需要处理为int类型
    var sum C.int = 0
    for i := 0; i < int(length); i++ {
        sum += dataSlice[i]
    }
    
    return sum
    // 或者返回长度
    // return length
}

func main() {
    // 空main函数,仅用于编译
}

修改C#代码

using System;
using System.Runtime.InteropServices;

public class GoFunctions
{
    [DllImport(@"test.dll", CallingConvention = CallingConvention.Cdecl)]
    public static extern int DoInt(IntPtr dataX, int length);
    
    public static int CallDoInt(int[] data)
    {
        // 分配非托管内存
        IntPtr ptr = Marshal.AllocHGlobal(data.Length * sizeof(int));
        
        try
        {
            // 复制数组到非托管内存
            Marshal.Copy(data, 0, ptr, data.Length);
            
            // 调用Go函数
            return DoInt(ptr, data.Length);
        }
        finally
        {
            // 释放内存
            Marshal.FreeHGlobal(ptr);
        }
    }
}

// 使用示例
class Program
{
    static void Main()
    {
        int[] bvals = { 1, 6, 8888, 4343, 3 };
        int result = GoFunctions.CallDoInt(bvals);
        Console.WriteLine($"Result: {result}");
    }
}

编译Go代码

go build -buildmode=c-shared -o test.dll main.go

关键点说明

  1. 参数类型转换:Go的[]int需要分解为C兼容的*C.int指针和C.int长度
  2. 调用约定:使用CallingConvention.Cdecl而不是StdCall
  3. 内存管理:C#端需要手动分配和释放非托管内存
  4. 类型安全:在Go中使用unsafe.Pointer进行类型转换时需要确保边界安全

这样修改后,Go函数就能正确接收C#传递的数组参数了。

回到顶部