如何将含联合体的C结构体转换为内存布局一致的C#结构体?
问题分析与解决方案
错误根源
你遇到的错误是因为C#中int[]是引用类型,它在结构体中存储的是指向托管数组对象的指针,而非数组的实际内存内容。CLR需要跟踪托管引用,不允许显式布局的结构体中出现引用类型字段与其他字段重叠,或引用类型字段之间重叠,因此抛出“偏移4处的对象字段对齐错误或被非对象字段重叠”的异常。
解决方案
方案1:使用unsafe固定数组(最贴合C语言内存布局,推荐)
该方案需要在项目属性中开启“允许unsafe代码”,直接对应C语言中数组的内存布局,结构体大小与C端完全一致。
// 对应C的s2结构体 public unsafe struct s2 { // 固定大小数组,直接在结构体内存中分配10个int的空间(40字节) public fixed int w[10]; } // 对应C的s3结构体 public unsafe struct s3 { public fixed int w[10]; } // 对应C的s1结构体(包含联合体) [StructLayout(LayoutKind.Explicit)] public unsafe struct s1 { [FieldOffset(0)] public int i; // 联合体成员共享偏移4开始的内存区域 [FieldOffset(4)] public s2 u1; [FieldOffset(4)] public s3 u2; }
方案2:非unsafe显式布局结构体(无需开启unsafe)
通过手动声明数组的每个元素,避免使用引用类型,让结构体成为纯值类型的 blittable 结构体:
[StructLayout(LayoutKind.Sequential)] public struct s2 { // 手动声明10个int字段,对应C语言的int w[10] public int w0; public int w1; public int w2; public int w3; public int w4; public int w5; public int w6; public int w7; public int w8; public int w9; } [StructLayout(LayoutKind.Sequential)] public struct s3 { public int w0; public int w1; public int w2; public int w3; public int w4; public int w5; public int w6; public int w7; public int w8; public int w9; } [StructLayout(LayoutKind.Explicit)] public struct s1 { [FieldOffset(0)] public int i; [FieldOffset(4)] public s2 u1; [FieldOffset(4)] public s3 u2; }
内容的提问来源于stack exchange,提问作者nuub
相关产品推荐
相关产品推荐

