C# 使用 StructLayoutAttribute 时 C# /C++ 内存空间分配与成员对齐问题

1. 使用场景

公共语言运行时控制数据字段的类或结构在托管内存中的物理布局。但是,如果想要将类型传递到非托管代码,需要使用 StructLayout 属性。

 

2. 内存分配问题。

如果不显示的设置内存对齐方式(通过StructLayout.Pack属性决定), C#默认是以4个字节(byte)为单位,会出现“多分配”内存的情况。 例如:

Class Example
{
   public byte b1;
   public char c2;
   public int i3;
}

默认情况下(StructLayout.Pack = 4),Framework编译器会为example对象分配8个字节(字段c2后面会补齐2个byte )。每个成员的索引和大小结果为:

     Size: 8

     b1 Offset: 0, lenght =1, 

     c2 Offset: 1, length = 1,

     i3 offset: 4, length = 4

 

C++ 编译器的分配方式则为:

  Size: 6

     b1 Offset: 0, lenght =1, 

     c2 Offset: 1, length = 1,

     i3 offset: 2, length = 4

 

由于内存分配的大小不一致,导致在传递对象marshal的时候回出现问题!!

 

3. 解决方案。

3.1 通过设置StructLayout.Pack的值来达到内存大小分配一致。

例如在上面的例子中,设置StructLayout.Pack =2 或者 StructLayout.Pack =1. 但是这种方法可能会因为硬件约束导致性能或者其他问题。

 

3.2 通过预留字段来“补齐”内存分配。

这种做法在实际项目中使用较多,既保证了长度一致,也为以后扩展提供了一种容错的可能。 如果采取这种方式,重新定义如下:

Class Example
{
   public byte b1;
   public char c2;
   public int i3;
   
   [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
   public byte[] reserved;
}

至此,C#和C++分配的内存大小同为8,问题解决  :)  

 

 

 

posted @ 2015-12-04 16:17  TonyZhang24  阅读(1456)  评论(0编辑  收藏  举报