C#-struct实例字段的内存布局(Layout)和大小(Size)

C#【高级篇】StructLayout特性是什么?怎么用? 阅读详情
AI摘要

本文详细介绍了C#中struct类型的内存布局控制方法,包括默认顺序排列、内存对齐以及自定义排列方式。通过示例演示了如何使用StructLayoutAttribute特性来调整struct实例在内存中的布局,旨在减少内存消耗并提高性能。

转自:http://blog.youkuaiyun.com/masterft/article/details/1699009


struct实例字段的内存布局(Layout)和大小(Size)


        在C/C++中,struct类型中的成员的一旦声明,则实例中成员在内存中的布局(Layout)顺序就定下来了,即与成员声明的顺序相同,并且在默认情况下总是按照结构中占用空间最大的成员进行对齐(Align);当然我们也可以通过设置或编码来设置内存对齐的方式.
        然而在.net托管环境中,CLR提供了更自由的方式来控制struct中Layout:我们可以在定义struct时,在struct上运用StructLayoutAttribute特性来控制成员的内存布局。默认情况下,struct实例中的字段在栈上的布局(Layout)顺序与声明中的顺序相同,即在struct上运用[StructLayoutAttribute(LayoutKind.Sequential)]特性,这样做的原因是结构常用于和非托管代码交互的情形。如果我们正在创建一个与非托管代码没有任何互操作的struct类型,我们很可能希望改变C#编译器的这种默认规则,因此LayoutKind除了Sequential成员之外,还有两个成员Auto和Explicit,给StructLayoutAttribute传入LayoutKind.Auto可以让CLR按照自己选择的最优方式来排列实例中的字段;传入LayoutKind.Explicit可以使字段按照我们的在字段上设定的FieldOffset来更灵活的设置字段排序方式,但这种方式也挺危险的,如果设置错误后果将会比较严重。下面就看几个示例,算下四个struct各占多少Byte?

1.[StructLayout(LayoutKind.Sequential)]

struct StructDeft//C#编译器会自动在上面运用[StructLayout(LayoutKind.Sequential)]
{
    
bool i;  //1Byte

    double c;//8byte
    bool b;  //1byte
}
    

        sizeof(StructDeft)得到的结果是24byte!啊哈,本身只有10byte的数据却占有了24byte的内存,这是因为默认(LayoutKind.Sequential)情况下,CLR对struct的Layout的处理方法与C/C++中默认的处理方式相同(8+8+8=24),即按照结构中占用空间最大的成员进行对齐(Align)。10byte的数据却占有了24byte,严重地浪费了内存,所以如果我们正在创建一个与非托管代码没有任何互操作的struct类型,最好还是不要使用默认的StructLayoutAttribute(LayoutKind.Sequential)特性。 

2.[StructLayout(LayoutKind.Explicit)]

[StructLayout(LayoutKind.Explicit)]
struct
 BadStruct
{
    [FieldOffset(
0
)]
    
public bool i;  //1Byte

    [FieldOffset(0)]
    
public double c;//8byte

    [FieldOffset(0)]
    
public bool b;  //1byte

}

        sizeof(BadStruct)得到的结果是9byte,显然得出的基数9显示CLR并没对结构体进行任何内存对齐(Align);本身要占有10byte的数据却只占了9byte,显然有些数据被丢失了,这也正是我给struct取BadStruct作为名字的原因。如果在struct上运用了[StructLayout(LayoutKind.Explicit)],计算FieldOffset一定要小心,例如我们使用上面BadStruct来进行下面的测试:

StructExpt e = new StructExpt();
e.c 
= 0
;
e.i 
= true
;
Console.WriteLine(e.c);

        输出的结果不再是0了,而是4.94065645841247E-324,这是因为e.c和e.i共享同一个byte,执行“e.i = true;时”也改变了e.c,CPU在按照浮点数的格式解析e.c时就得到了这个结果.所以在运用LayoutKind.Explicit时千万别吧FieldOffset算错了:) 

3.[StructLayout(LayoutKind.Auto)]
        sizeof(StructAuto)得到的结果是12byte。下面来测试下这StructAuto的三个字段是如何摆放的:

unsafe
{
      StructAuto s 
= new
 StructAuto();
      Console.WriteLine(
string.Format("i:{0}", (int)&
(s.i)));
      Console.WriteLine(
string.Format("c:{0}", (int)&
(s.c)));
      Console.WriteLine(
string.Format("b:{0}", (int)&
(s.b)));
}

// 测试结果:
i:1242180
c:
1242172
b:
1242181

        即CLR会对结构体中的字段顺序进行调整,将i调到c之后,使得StructAuto的实例s占有尽可能少的内存,并进行4byte的内存对齐(Align),字段顺序调整结果如下图所示:


4.空struct实例的Size

struct EmptyStruct{}

    无论运用上面LayoutKind的Explicit、Auto还是Sequential,得到的sizeof(EmptyStct)都是1byte。 

结论:
        默认(LayoutKind.Sequential)情况下,CLR对struct的Layout的处理方法与C/C++中默认的处理方式相同,即按照结构中占用空间最大的成员进行对齐(Align);
        使用LayoutKind.Explicit的情况下,CLR不对结构体进行任何内存对齐(Align),而且我们要小心就是FieldOffset;
        使用LayoutKind.Auto的情况下,CLR会对结构体中的字段顺序进行调整,使实例占有尽可能少的内存,并进行4byte的内存对齐(Align)。 


另外有关StructLayout的详细信息,查看https://msdn.microsoft.com/en-us/library/system.runtime.interopservices.structlayoutattribute.aspx

遗传算法工程落地:算子协同、参数耦合与收敛稳定性实战 遗传算法(GA)作为经典进化优化方法,其核心价值在于解决非凸、非线性、多约束的复杂工程优化问题。理解其底层原理不能止步于选择、交叉、变异三步流程,而需深入算子协同机制、参数敏感性边界及收敛性陷阱识别等关键维度。尤其在实数编码、SBX交叉、多项式变异与精英保留策略协同下,算法才能兼顾探索能力与开发精度。技术价值体现在显著提升解质量鲁棒性、压缩收敛代数、降低评估资源消耗,广泛应用于智能排产、结构优化、超参搜索与工业数字孪生等场景。本文聚焦真实产线级调参经验,揭示参数耦合效应与收敛稳定性之间的本质关联。 阅读详情

相关推荐

C#中结构(struct)的部分初始化和完全初始化实例分析

本文实例分析了C#中结构(struct)的部分初始化和完全初始化,分享给大家供大家参考。具体分析如下: 假设有这样一个值类型struct,如下所示: public struct Size { public int Length; public int Width; public int Area() { return Length*Width; } } 一、客户端,给所有struct字段初始化后调用方法 class Program { static void Main(string[] args) { Siz

[StructLayout(LayoutKind.Sequential) ] 是什么意思

[StructLayout(LayoutKind.Sequential) ]是结构体排序问题;首先介绍一下 结构体和类的区别 :类是按引用传递 结构体是按值传递进入正题:结构体是由若干成员组成的.布局有两种1.Sequential,顺序布局,比如struct S1{  int a;  int b;}那么默认情况下在内存里是先排a,再排b也就是如果能取到a的地址,和b的地址,则相差一个i

qianhe_he的专栏 3833

SRAM compiler选项中 Soft Error Repair (SER)

引起的瞬时故障,可能会影响 SRAM 中存储的数据。SER 功能通过某种机制检测并修复这些错误,从而提高存储器的可靠性。在 SRAM 编译器中,

hzmscut的博客 1154

C#-StructLayoutAttribute(结构体布局)

先让我们看四个首要的根基概念:   1.数据类型自身的对齐值:   对于char型数据,其自身对齐值为1,对于short型为2,对于int,float,double类型,其自身对齐值为4,单位字节。   2.结构 体或者类的自身对齐值:其成员中自身对齐值最大的那个值。   3.指定对齐值:#pragma pack (value)时的指定对齐值value。   4.数据成员、结构 体和类的有效对齐值:自身对齐值和指定对齐值中小的那个值。 有 了这些值,我们就可以很方便的来讨论具体数据结构的成员和其

qq_32584715的博客 2346

Linux显卡管理避坑指南:为什么Xorg总是占用你的NVIDIA GPU?

本文深入解析了在Linux系统上,尤其是双显卡笔记本中,Xorg显示服务器进程占用NVIDIA GPU的根本原因。文章从Xorg的驱动加载机制和NVIDIA驱动的独占性入手,详细对比了禁用配置文件、手动配置xorg.conf、使用官方PRIME方案以及切换到Wayland等主流解决方案的优缺点与适用场景,旨在帮助用户有效释放GPU资源,确保深度学习、游戏等计算任务能独占显卡性能。

xgboost6farmer的博客 268

CF鼠标宏防封指南:手把手教你调校罗技G HUB压枪脚本的延迟与随机数

本文详细解析了如何通过罗技G HUB的Lua脚本功能调校鼠标宏,实现拟真操作体验。重点介绍了随机数应用、动态后坐力补偿和智能操作序列等高级技术,帮助玩家在不违反游戏规则的前提下提升操作精度。

weixin_26841957的博客 334

C# struct实例字段的内存布局(Layout)和大小(Size)

在C/C++中,struct类型中的成员的一旦声明,则实例中成员在内存中的布局(Layout)顺序就定下来了,即与成员声明的顺序相同,并且在默认情况下总是按照结构中占用空间最大的成员进行对齐(Align);当然我们也可以通过设置或编码来设置内存对齐的方式.         然而在.net托管环境中,CLR提供了更自由的方式来控制struct中Layout:我们可以在定义struct时,在stru

superhoy的专栏 1953

XGBoost调参新姿势:Bayesian优化实战指南(附完整代码)

本文详细介绍了如何使用Bayesian优化方法高效调优XGBoost模型参数。通过解析Bayesian优化核心原理和XGBoost关键参数,提供完整的实战代码示例,帮助读者掌握这一智能调参技术,显著提升模型性能。文章特别适合机器学习工程师和数据科学家阅读。

weixin_42536058的博客 366

.net托管环境下struct实例字段的内存布局(Layout)和大小(Size)

.net托管环境下struct实例字段的内存布局(Layout)和大小(Size) 在C/C++中,struct类型中的成员的一旦声明,则实例中成员在内存中的布局(Layout)顺序就定下来了,即与成员声明的顺序相同,并且在默认情况下总是按照结构中占用空间最大的成员进行对齐(Align);当然我们也可以通过设置或编码来设置内存对齐的方式,有关C/C++中(设置)内存对齐的讨论,可以参考...

weixin_42627361的博客 50

hMailServer安装配置

hMailServer安装配置 使用宝塔面板上的宝塔邮件服务器2.1版本,进行安装hMailServer。 宝塔在安装hMailServer是有做了一些配置,如果是手工安装需要注意一下配置点: 1、\hMailServer\Bin 目录下增加mysql连接文件libmysql.dll,要去下载32位的。 libmysql.dll下载 链接:https://pan.baidu.com/s/1YGJXzjowlJ9n_MiqB4xiqw 提取码:wz90 2、 需要提前安装mysql,并创建hM.

王者的博客 5868

阿里云人工智能工程师ACA认证免费课程学习笔记

阿里云人工智能工程师ACA认证免费课程学习笔记

engchina的专栏 2014

C# Struct的内存布局

问题:请说出以下struct的实例大小以及内存布局 [code="C#"] struct Struct1 { public byte a; public short b; public string c; public int d; } struct Struct2 { ...

dazhilao 370

告别License烦恼:手把手教你用VS Code+Cppcheck搭建免费的MISRA-C代码检查环境

本文详细介绍了如何使用VS Code和开源工具Cppcheck搭建免费的MISRA-C代码检查环境,帮助开发者规避商业工具的高额License费用。通过四步环境搭建和实战技巧,实现高效的代码静态检查,提升嵌入式开发的安全性和可靠性。

weixin_42523326的博客 248

[StructLayout(LayoutKind.Sequential)]struct实例字段的内存布局(Layout)和大小(Size)

struct实例字段的内存布局(Layout)和大小(Size)         在C/C++中,struct类型中的成员的一旦声明,则实例中成员在内存中的布局(Layout)顺序就定下来了,即与成员声明的顺序相同,并且在默认情况下总是按照结构中占用空间最大的成员进行对齐(Align);当然我们也可以通过设置或编码来设置内存对齐的方式.         然而在.net托管环境中,CLR

阿拉平平的专栏 7919

仿真学习系列(二):ADS仿真直观理解方波与频谱分量的关系

在高速电路设计中,我们常常听到一句话:“信号其实不是电压在传输,而是频率在传播。” 这句话看似抽象,却揭示了信号世界的核心本质——任何时域波形,都可以被拆解为一系列不同频率的正弦波。 那么,一个看似简单的方波,究竟由哪些频率成分组成?为什么在示波器上,有的方波上升沿又快又“方”,而有的却“圆润”得多?这些差异背后,隐藏的正是高频分量的力量。 本文将通过使用 Keysight ADS,从零搭建仿真电路,直观地观察方波与其谐波成分之间的关系。

案例文章,高速信号 814

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

struct实例字段的内存布局(Layout)和大小(Size)

转帖: struct实例字段的内存布局(Layout)和大小(Size) 在C/C++中,struct类型中的成员的一旦声明,则实例中成员在内存中的布局(Layout)顺序就定下来了,即与成员声明的顺序相同,并且在默认情况下总是按照结构中占用空间最大的成员进行对齐(Align);当然我们也可以通过设置或编码来设置内存对齐的方式. 然而在.net托管环境中,C...

weixin_30256901的博客 96

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

net托管环境下struct实例字段的内存布局(Layout)和大小(Size) zt

net托管环境下struct实例字段的内存布局(Layout)和大小(Size)     在C/C++中,struct类型中的成员的一旦声明,则实例中成员在内存中的布局(Layout)顺序就定下来了,即与成员声明的顺序相同,并且在默认 情况下总是按照结构中占用空间最大的成员进行对齐(Align);当然我们也可以通过设置或编码来设置内存对齐的方式,有关C/C++中(设置)内存对齐 的讨...

weixin_33895604的博客 70

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

上一篇: 浅析C#中的Attribute
下一篇: C#中的IDisposable模式用法详解
骑行的蜗牛
博客等级 码龄21年 107粉丝 86原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值