C# Struct的内存布局问题解答

问题:请说出以下struct的实例大小以及内存布局

代码如下:

struct Struct1
{
    public byte a;
    public short b;
    public string c;
    public int d;
}

struct Struct2
{
    public byte a;
    public long b;
    public byte c;
    public string d;
}

struct Struct3
{
    byte a;
    byte b;
    long c;
}

struct Struct4
{
    byte a;
    long b;
    byte c;
}

一会再看答案,看看和你的理解是不是有很大的出入?其实struct和class的内存布局都是由StructLayoutAttribute的构造参数:LayoutKind枚举决定的,struct由编译器添加LayoutKind.Sequential,class由编译器添加的是LayoutKind.Auto。而Sequential通过实验数据可以总结如下:

1. 对于不带引用类型的struct:按照定义的顺序排列,内存布局和c,c++规则相同。比如:

Byte a;

Byte b;

Long c;

的大小是 a,b填充4字节,c填充8字节

Byte a

Long c

Byte b

的大小是 a填充8字节,c填充8字节,b填充8字节

2. 对于带有引用类型的struct:大于4字节的字段 -> 引用字段 ->  小于4字节的字段

对于小于4字节的字段按照大小排列,如果大小相同按照定义顺序,内存布局和规则1相同。不过这里有个需要注意的地方就是如果字段还是一个struct类型的,那么这个字段始终排在最后。

所以上面的答案是:

Struct1:c(4) -> d(4) -> b(2) ->a(2)

Struct2:b(8) -> d(4) -> a(1)c(1)填充2字节

Struct3: a(1)b(1)填充2字节 -> c(8)

Struct4:a(1)填充7字节->b(8)->c(1)填充7字节

如果你想亲自动手实验一下的话需要使用SOS.dll进行调试(关于SOS配置和使用入门的文章博客园上有很多)以struct1为例:

Struct1s1 = new Struct1();

s1.a = 1;

s1.b = 15;

s1.c = "c";

s1.d = 32;

.load sos

已加载扩展C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\sos.dll

!clrstack -a

PDB symbol for mscorwks.dll not loaded

OS Thread Id: 0x15fc (5628)

ESP       EIP

0041ee3c 03ba01aa Test_Console.Class12.Main()

LOCALS:

0x0041ee84 = 0x01b02b0c

0x0041ee74 = 0x00000020

0x0041ee68 = 0x00000000

0x0041ee50 = 0x00000000

0041f104 6ebd1b4c [GCFrame: 0041f104]

.load sos

已加载扩展C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\sos.dll

!name2ee *!Test_Console.Struct1 //得到Struct1的方法表地址

PDB symbol for mscorwks.dll not loaded

Module: 6d5d1000 (mscorlib.dll)

--------------------------------------

Module: 00192c5c (Test_Console.exe)

Token: 0x02000012

MethodTable: 00193828

EEClass: 007a45b4

Name: Test_Console.Struct1

!clrstack -a //得到struct1实例的栈上地址

OS Thread Id: 0x1438 (5176)

ESP       EIP

003eef0c 008f00c9 Test_Console.Class12.Main()

LOCALS:

0x003eef1c = 0x01c12b0c

003ef17c 6ebd1b4c [GCFrame: 003ef17c]

!dumpvc 00193828 0x003eef1c //查看值类型的layout

Name: Test_Console.Struct1

MethodTable 00193828

EEClass: 007a45b4

Size: 20(0x14) bytes

Fields:

MT    Field   Offset                 Type VT     Attr    Value Name

6d84340c  400001c        a          System.Byte  1 instance        1 a

6d83e910  400001d        8         System.Int16  1 instance       15 b

6d8408ec  400001e        0        System.String  0 instance 01c12b0c c

6d842b38  400001f        4         System.Int32  1 instance       32 d

在内存窗口中可以看到内存布局为:

0x003EEF1C  01c12b0c 00000020 0001000f

这里我要说明下使用dumpvc后会给出一个size,这里是20字节,比我们计算的结果多出8个字节,我的理解是因为引用类型有附加的8字节(syncblkindex + methodtableaddress)所以这里的size也加上了8.

(0)

相关推荐

  • C#结构体特性实例分析

    本文实例讲述了C#结构体特性.分享给大家供大家参考.具体如下: 结构体的定义: 结构体也可以象类一样可以单独定义. class a{}; struct a{}; 结构体也可以在名字前面加入控制访问符. public struct student{}; internal struct student{}; 如果结构体student没有publice或者internal的声明 类program就无法使用student结构定义 obj对象 如果结构体student的元素没有public的声明,对象ob

  • C#基础语法:结构和类区别详解

    结构和类很相似,也可以包含数据成员和函数成员,但是与类不同,结构是一种值类型,(我们可以理解为一种特殊的值类型所以不存在继承的问题)为其分配数据不需要从托管堆中分配存储器.结构类型的变量直接包含了该结构的数据,而类类型的变量所包含的只是对相应对象的一个引用.  下面总结一下结构和类的不同: 1.结构是值类型,对结构类型的变量赋值将创建所赋值的一个副本. 2.结构实例的默认值不是null,而是具有默认值的初始值. 3.在结构和类中this的意义不一样. 4.结构不支持继承(所以结构成员的声明可访问

  • 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

  • 轻松学习C#的结构和类

    类和结构是.NET Framework中的同样类型系统的两种基本构造.两者在本质上都属于数据结构,封装这一组整体作为一个逻辑单位的数据和行为.数据和行为是该类或结构的"成员",它们包含着各自的方法,属性和事件等.        结构        结构是C#程序员用来定义自己的值类型的最普遍的机制.结构比枚举更强大,因为它提供方法,字段,操作符和访问控制等.        结构与类很相似,都表示可以包含数据成员和函数成员的数据结构.但是,与类不同,结构是一种值类型,并且不需要堆分配.结

  • C#中类与结构的区别实例分析

    类与结构是C#程序设计中基本的数据类型,而初学者往往不能很好的分清二者之间的区别.本文就以附带实例形式加以说明.具体如下: 一.基本概念: 类:引用类型,存储在堆中,栈中存储引用地址,在方法的传输中只是传输地址的引用,修改指向的对象会影响原有对象的值,传输中消耗内存小. 结构:值类型,存储在堆栈中,传输过程中传输整个对象的副本,修改指向对象的值不会影响原有的对象,传输中消耗内存大. 二.实例代码如下: class Program { static void Main(string[] args)

  • C#中struct和class的区别详解

    本文详细分析了C#中struct和class的区别,对于C#初学者来说是有必要加以了解并掌握的. 简单来说,struct是值类型,创建一个struct类型的实例被分配在栈上.class是引用类型,创建一个class类型实例被分配在托管堆上.但struct和class的区别远不止这么简单. 概括来讲,struct和class的不同体现在: ● 类是引用类型,struct是值类型 ● 在托管堆上创建类的实例,在栈上创建struct实例 ● 类实例的赋值,赋的是引用地址,struct实例的赋值,赋的是

  • C++联合体转换成C#结构的实现方法

    本文实例主要参考MSDN:http://msdn.microsoft.com/zh-cn/library/ya9bz4ha%28v=vs.80%29.aspx 最近因为项目中遇到了C++联合体转换成C#结构的情况,查了很多资料才转换成功. 备注:对于官方这个UNION示例,我的简单理解,就是这类UNION做法,可适当代替IF ELSE 之类操作. 解决问题:如果只接收视频解码数据,而从不接收音频数据,那么是否可以直接定义结构体,并以此来获取视频数据. /// <summary> /// * @

  • 深入探讨C#中的结构struct

    一.结构和类的区别 1.结构的级别和类一致,写在命名空间下面,可以定义字段.属性.方法.构造方法也可以通过关键字new创建对象. 2.结构中的字段不能赋初始值. 3.无参数的构造函数无论如何C#编译器都会自动生成,所以不能为结构定义一个无参构造函数. 4.在构造函数中,必须给结构体的所有字段赋值. 5.在构造函数中,为属性赋值,不认为是对字段赋值,因为属性不一定是去操作字段. 6.结构是值类型,在传递结构变量的时候,会将结构对象里的每一个字段复制一份拷贝到新的结构变量的字段中. 7.不能定义自动

  • c#入门之枚举和结构体使用详解(控制台接收字符串以相反的方向输出)

    枚举.结构枚举的类型有限(short.byte...)且是相同的,在MSDN上找到枚举的一些示例,觉得这个还不错: 复制代码 代码如下: enum myWeekDay { Monday = 1, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday };int i = 3;myWeekDay today = (myWeekDay)i; 枚举是需要先声明的,然后再通过新建一个变量(today)为枚举类型来使用.枚举默认的基本类型值从0开始,递

  • C#中结构体和字节数组转换实现

    最近在使用结构体与字节数组转化来实现socket间数据传输.现在开始整理一下.对于Marshal可以查阅msdn,关于字节数组与结构体转代码如下: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; using System.Runtime.InteropServices; namespace FileSendClient { [StructL

  • c# DataTable与不同结构实体类转换的方法实例

    在实际开发过程中,或者是第三方公司提供的数据表结构,与我们系统中的实体类字段不对应,遇到这样我们怎么处理呢?可能有人会说,在转换时创建一个实体对象,对表里的数据逐行遍历来实例化这个实体对象不就完了.的确没错,这方法可行,但是这个方法效率极低,遇到亿万数据的话那就要实例化亿万个对象,由此可见它的效率了.先看一下我的实体类 复制代码 代码如下: /// <summary>/// 具体的实体类,和数据表中不同/// </summary>public class Person{    [D

  • 深入解析C#编程中struct所定义的结构

    结构是使用 struct 关键字定义的,例如: public struct PostalAddress { // Fields, properties, methods and events go here... } 结构与类共享大多数相同的语法,但结构比类受到的限制更多: 在结构声明中,除非字段被声明为 const 或 static,否则无法初始化. 结构不能声明默认构造函数(没有参数的构造函数)或析构函数. 结构在赋值时进行复制.将结构赋值给新变量时,将复制所有数据,并且对新副本所做的任何修

  • C#枚举类型与结构类型实例解析

    本文以C#实例讲解了枚举类型与结构类型的用法,程序主要是通过个人电话本演示枚举类型与结构类型的用法,具体代码如下所示: using System; class ID { //定义枚举类型 public enum Sex { male, female };//注意别忘了这里的分号 //定义电话本的结构类型 public struct TelBook { public string name; public Sex sex;//性别类型为枚举类型 public string number; } //

随机推荐