You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#调用C DLL:Marshal含字符串数组的返回结构体时崩溃求助

解决C#调用C DLL时Marshal返回结构体的崩溃问题

我来帮你搞定这个问题!你怀疑指针偏移计算出错完全找对了方向,咱们一步步拆解问题根源:

核心问题:size_t的类型映射错误导致指针偏移失效

C语言里的size_t是平台相关的无符号整数类型——32位系统下占4字节,64位系统下占8字节。你用ulong对应它,再通过Marshal.SizeOf(typeof(ulong))计算偏移,这在32位平台下直接踩坑:ulong在C#里固定是8字节,而实际size_t只占4字节,导致指针被多偏移了4字节,指向错误的内存区域,读取char**时自然会崩溃。

正确的解决方案步骤

1. 定义与C结构体严格匹配的C#结构体

首先要确保C#侧的结构体和C侧内存布局完全一致,用IntPtr对应size_t(IntPtr大小会自动适配32/64位平台):

假设你的C结构体定义是:

typedef struct {
    size_t string_count;
    char** string_array;
} ConfigStruct;

对应的C#结构体应该这样写:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct ConfigStruct
{
    // 用IntPtr对应C的size_t,自动适配平台指针大小
    public IntPtr StringCount;
    // 对应C的char**
    public IntPtr StringArrayPtr;
}

2. 正确解析返回的结构体指针

不要手动计算字段偏移,直接用Marshal.PtrToStructure把C返回的结构体指针解析成C#结构体实例,彻底避免手动偏移的错误:

public Dictionary<string, string> ConvertConfigStructToDict(IntPtr structPtr)
{
    // 直接把C的结构体指针marshal成C#结构体对象
    ConfigStruct config = Marshal.PtrToStructure<ConfigStruct>(structPtr);
    
    // 把IntPtr类型的count转成整数(自动适配平台)
    int count = (int)config.StringCount;
    // 获取char**的指针
    IntPtr stringsPtr = config.StringArrayPtr;
    
    // 调用你的ConvertStringArray方法处理字符串数组
    string[] stringArray = ConvertStringArray(stringsPtr, count);
    
    // 假设字符串数组是键值对形式,转成字典
    var configDict = new Dictionary<string, string>();
    for (int i = 0; i < count; i += 2)
    {
        if (i + 1 < count)
            configDict[stringArray[i]] = stringArray[i + 1];
    }
    
    return configDict;
}

3. 确保ConvertStringArray的逻辑正确

你的ConvertStringArray单独测试char**时正常,但结合结构体使用时要注意:每个元素是char*的指针,需要先读取指针地址再转成字符串:

public string[] ConvertStringArray(IntPtr arrayPtr, int count)
{
    string[] result = new string[count];
    
    for (int i = 0; i < count; i++)
    {
        // 读取第i个char*的指针地址(每个指针占IntPtr.Size字节)
        IntPtr strPtr = Marshal.ReadIntPtr(arrayPtr, i * IntPtr.Size);
        // 把C的char*转成C#字符串
        result[i] = Marshal.PtrToStringAnsi(strPtr);
        
        // 注意:如果C DLL分配了字符串内存,一定要调用DLL提供的释放函数,避免内存泄漏
    }
    
    return result;
}

额外注意事项

  • 平台一致性:确保你的C DLL和C#程序同为32位或64位,否则指针大小不匹配会引发各种内存错误。
  • 内存释放:如果C DLL返回的结构体和字符串数组是动态分配的,务必调用DLL提供的释放函数。
  • 调用约定:在DllImport时指定正确的CallingConvention(比如Cdecl),和C DLL的编译约定保持一致。

内容的提问来源于stack exchange,提问作者KrissCode

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 09:04:07