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

1. 使用场景

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

 

2. 内存分配问题。

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

1
2
3
4
5
6
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 通过预留字段来“补齐”内存分配。

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

1
2
3
4
5
6
7
8
9
Class Example
{
   public byte b1;
   public char c2;
   public int i3;
    
   [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
   public byte[] reserved;
}

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

 

 

 

posted @   TonyZhang24  阅读(1479)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示