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

C#向C DLL封送含IntPtr的结构体时返回数据损坏错误排查

核心问题定位

两个高概率根因,按优先级排序:

  • 结构体对齐不匹配触发堆内存越界
    你给C#封送结构体标记了Pack = 1,强制按1字节紧凑对齐,但C端代码没有通过#pragma pack修改默认对齐规则,会采用平台自然对齐:
    64位环境下C结构体_TAG_Data的最大成员是8字节长的void*指针,因此结构体整体按8字节对齐,布局为:前8字节存data指针,接下来4字节存size字段,最后自动填充4字节padding保证结构体大小为8的整数倍,即整个结构体占16字节。
    你定义的MyData_Packed因为Pack=1总大小仅为12字节,Marshal.AllocHGlobal也只分配了12字节内存。C端代码按16字节大小访问结构体时,会越界读取分配块外的4字节内存——Windows堆会在每个分配块前后插入校验标记,越界读取会直接触发堆校验逻辑,返回数据损坏错误,和你缓冲区里的实际业务数据无关。你在内存监视器里看到前12字节内容正确,不代表整个结构体的内存访问合法。
  • 调用约定不匹配导致栈错位
    你的DllImport特性没有显式指定调用约定,.NET默认采用StdCall(Winapi平台默认),但纯C编译的DLL默认导出函数使用Cdecl调用约定。二者参数压栈顺序一致,但栈清理逻辑不同,会导致函数返回后栈指针错位,参数、返回值读取异常,也可能抛出数据损坏类错误。
修复代码

直接修改两处定义即可:

  1. 调整封送结构体的对齐配置,去掉强制1字节对齐的设置,使用平台默认对齐规则:
[StructLayout(LayoutKind.Sequential)]
struct MyData_Packed
{
    public IntPtr data;
    public UInt32 size;
}

修改后可通过断点验证:64位环境下Marshal.SizeOf(typeof(MyData_Packed))返回16,32位环境下返回8,和C端结构体大小完全一致。
2. 为P/Invoke方法显式指定Cdecl调用约定:

[DllImport("Some.dll", EntryPoint = "ParseData", SetLastError = true, CallingConvention = CallingConvention.Cdecl)]
private static extern Int32 ParseData_Native(IntPtr result, UInt64 parameter, ref Int32 value);
进一步简化与排查方案

如果修改上述两点后问题仍然存在,按以下步骤处理:

  • 简化手动封送逻辑,避免手动分配结构体内存带来的错误。可以直接将P/Invoke声明改为传递结构体引用,CLR会自动完成结构体封送的内存分配、对齐处理,无需手动调用Marshal.AllocHGlobal和Marshal.StructureToPtr:
    [DllImport("Some.dll", EntryPoint = "ParseData", SetLastError = true, CallingConvention = CallingConvention.Cdecl)]
    private static extern Int32 ParseData_Native(ref MyData_Packed result, UInt64 parameter, ref Int32 value);
    
    调用时直接传入ref MyResultPacked即可,大幅减少手动内存操作的出错概率。
  • 确认进程和DLL的架构匹配:如果DLL是64位版本,就将C#项目的平台目标设置为x64;如果是32位版本就设置为x86,不要使用AnyCPU配置,避免架构不匹配导致指针长度错误。
  • 确认非托管缓冲区的对齐要求:部分C库要求传入的二进制缓冲区按16字节甚至更高地址对齐,Marshal.AllocHGlobal返回的内存默认按8字节对齐,如果库有更高对齐要求,需要手动调整缓冲区起始地址到符合要求的对齐边界。
  • 非托管内存使用完成后,记得调用Marshal.FreeHGlobal释放手动分配的缓冲区和结构体内存,避免内存泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 21:24:30