【转】C/C++ struct/class/union内存对齐

原文链接:http://www.cnblogs.com/Miranda-lym/p/5197805.html

struct/class/union内存对齐原则有四个:

1).数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小或者成员的子成员大小(只要该成员有子成员,比如说是数组,结构体等)的整数倍开始(比如int在32位机为4字节, 则要从4的整数倍地址开始存储),基本类型不包括struct/class/uinon。

2).结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部"最宽基本类型成员"的整数倍地址开始存储.(struct a里存有struct b,b里有char,int ,double等元素,那b应该从8的整数倍开始存储.)。

3).收尾工作:结构体的总大小,也就是sizeof的结果,.必须是其内部最大成员的"最宽基本类型成员"的整数倍.不足的要补齐.(基本类型不包括struct/class/uinon)。

4).sizeof(union),以结构里面size最大元素为union的size,因为在某一时刻,union只有一个成员真正存储于该地址。

实例解释:下面以class为代表

No.1

class Data
{
    char c;
    int a;
};

cout << sizeof(Data) << endl;

No.2

class Data
{
    char c;
    double a;
};

cout << sizeof(Data) << endl;

显然程序No.1 输出的结果为 8    No.2 输出的结果为 16 .

No.1最大的数据成员是4bytes,1+4=5,补齐为4的倍数,也就是8。而No.2为8bytes,1+8=9,补齐为8的倍数,也就是16。

No.3

class Data
{
    char c;
    int a;
    char d;
};

cout << sizeof(Data) << endl;

No.4

class Data
{
    char c;
    char d;
    int a;
};

cout << sizeof(Data) << endl;

No.3运行结果为 12

No.4运行结果为 8

class中的数据成员放入内存的时候,内存拿出一个内存块来,数据成员们排队一个一个往里放,遇到太大的,不是把自己劈成两半,能放多少放多少,而是等下一个内存块过来。这样的话,就可以理解为什么No.3,No.4两端的代码输出结果不一样了,因为左边是1+(3)+4+1+(3)=12,而右边是1+1+(2)+4=8。括号中为补齐的bytes。

No.5

class BigData
{
    char array[33];
};

class Data
{
    BigData bd;
    int integer;
    double d;
};

cout << sizeof(BigData) << "   " << sizeof(Data) << endl;

No.6

class BigData
{
    char array[33];
};

class Data
{
    BigData bd;
    double d;
};

cout << sizeof(BigData) << "   " << sizeof(Data) << endl;

No.5和No.6运行结果均为: 48

在默认条件下,内存对齐是以class中最大的那个基本类型为基准的,如果class中有自定义类型,则递归的取其中最大的基本类型来参与比较。在No.5和No.6中内存块一个接一个的过来接走数据成员,一直到第5块的时候,BigData里只剩1个char了,将它放入内存块中,内存块还剩7个bytes,接下来是个int(4bytes),能够放下,所以也进入第5个内存块,这时候内存块还剩3bytes,而接下来是个double(8bytes),放不下,所以要等下一个内存快到来。因此,No.5的Data的size=33+4+(3)+8=48,同理No.6应该是33+(7)+8=48。

顺便提一下Union: 共用体表示几个变量共用一个内存位置,在不同的时间保存不同的数据类型和不同长度的变量。在union中,所有的共用体成员共用一个空间,并且同一时间只能储存其中一个成员变量的值。

以上内容部分转载自http://www.cnblogs.com/biyeymyhjob/archive/2012/09/07/2674992.html


拓展:

一、32位操作系统下各种数据类型所占的字节数

1、整型

int                         4字节                      

long int                  4字节

short int                   2字节

unsigned long int     4字节

unsigned short int    2字节

2、字符型

char                          1字节

unsigned char           1字节

3、浮点型

float                              4字节

double                          8字节

long double                  8字节

unsigned long double   8字节

unsigned double           4字节

4、字符串型

string                           32字节

5、指针类型

所有类型的指针都是 4字节 (但是在64位下为8字节)

二、字节对齐原则

在系统默认的对齐方式下:每个成员相对于这个结构体变量地址的偏移量正好是该成员类型所占字节的整数倍,且最终占用字节数为成员类型中最大占用字节数的整数倍。

三、C++类中的数据成员也遵循以上对齐原则,即:

1.在不考虑(或者说在没有)虚函数和虚继承的情况下,sizeof(自定义类)也按照类似上面的方式来计算。

2.但如果一个类拥有虚函数或者虚继承,则在数据成员的基础上相当于多一个指针类型的数据成员(位置在所有数据成员的前面),最后计算时加上即可。

3.静态(static)成员不在计算范围。

[简言之,类的大小与成员变量(非static数据成员变量)和虚函数指针有关(注意:虚函数中有一个指向虚函数列表的指针,无论有多少个虚函数都是占用一个字节的大小)]

4.如果一个类或者结构体不含有任何数据成员,且无虚函数以及虚继承,则sizeof()结构为1。

四、为什么要进行字节对齐?

  《Windows核心编程》里这样说:当CPU访问正确对齐的数据时,它的运行效率最高,当数据大小的数据模数的内存地址是0时,数据是对齐的。例如:WORD值应该是总是从被2除尽的地址开始,而DWORD值应该总是从被4除尽的地址开始,数据对齐不是内存结构的一部分,而是CPU结构的一部分。当CPU试图读取的数值没有正确的对齐时,CPU可以执行两种操作之一:产生一个异常条件;执行多次对齐的内存访问,以便读取完整的未对齐数据,若多次执行内存访问,应用程序的运行速度就会慢。

可参考webary的blog:http://www.cnblogs.com/webary/p/4721017.html

时间: 2024-10-11 05:41:46

【转】C/C++ struct/class/union内存对齐的相关文章

C/C++ struct/class/union内存对齐

struct/class/union内存对齐原则有四个: 1).数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小或者成员的子成员大小(只要该成员有子成员,比如说是数组,结构体等)的整数倍开始(比如int在32位机为4字节, 则要从4的整数倍地址开始存储),基本类型不包括struct/class/uinon. 2).结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部"

C/C++中的内存对齐 C/C++中的内存对齐

一.什么是内存对齐.为什么需要内存对齐? 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特 定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐. 字,双字,和四字在自然边界上不需要在内存中对齐.(对字,双字,和四字来说,自然边界分别是偶数地址,可以被4整除的地址,和可以被8整除的地址.)无论如何,为了提高程序的性能,数据结构(尤其是栈)应该尽可能

C++内存对齐方式

转自http://www.blogfshare.com/memory-alignment.html 一.什么是内存对齐.为什么需要内存对齐? 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特 定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐. 字,双字,和四字在自然边界上不需要在内存中对齐.(对字,双字,和四字来说,自然边界分别是偶数地址,可以

(转)c/c++内存对齐问题

struct/class/unio内存对齐: http://blog.csdn.net/microsues/article/details/6140329 class函数占用字节数问题: http://blog.csdn.net/debugingstudy/article/details/12657425

&lt;转&gt; Struct 和 Union区别 以及 对内存对齐方式的说明

转载地址:http://blog.csdn.net/firefly_2002/article/details/7954458 一.Struct 和 Union有下列区别: 1.在存储多个成员信息时,编译器会自动给struct第个成员分配存储空间,struct 可以存储多个成员信息,而Union每个成员会用同一个存储空间,只能存储最后一个成员的信息. 2.都是由多个不同的数据类型成员组成,但在任何同一时刻,Union只存放了一个被先选中的成员,而结构体的所有成员都存在. 3.对于Union的不同成

struct和Union的内存分配

eg: struct node{ char c ; int x ; }; 在你定义一个这个的node后, 系统给它分配的内存不是简单的就是sizeof(char)+sizeof(int)= 5 :  而是采用内存对齐的方式 . 首先在计算机中 , 会有一个默认的参数 , 即对齐膜数 , 一般默认为8字节 , 但可以通过在程序中添加如下命令来改变其值 #pragma pack(n) ; 在知道对齐模数后, 就可以开始说对齐规则了 1:在系统给其分配内存时 , 是安照你定义的先后的原则 , 比如说上

C#调用C++ 平台调用P/Invoke 结构体--内存对齐方式、union封装【七】

[1]内存对齐方式 C++代码: #pragma pack(push) #pragma pack(1) typedef struct _testStru2 { int iVal; char cVal; __int64 llVal; }testStru2; #pragma pack(pop) EXPORTDLL_API void Struct_PackN( testStru2 *pStru ) { if (NULL == pStru) { return; } pStru->iVal = 1; pS

struct内存对齐1:gcc与VC的差别

struct内存对齐:gcc与VC的差别 内存对齐是编译器为了便于CPU快速访问而采用的一项技术,对于不同的编译器有不同的处理方法. Win32平台下的微软VC编译器在默认情况下采用如下的对齐规则: 任何基本数据类型T的对齐模数就是T的大小,即sizeof(T).比如对于double类型(8字节),就要求该类型数据的地址总是8的倍数,而char类型数据(1字节)则可以从任何一个地址开始.Linux下的GCC奉行的是另外一套规则:任何2字节大小(包括单字节吗?)的数据类型(比如short)的对齐模

内存对齐与ANSI C中struct型数据的内存布局 【转】

转自:http://blog.chinaunix.net/uid-25909619-id-3032209.html 当在C中定义了一个结构类型时,它的大小是否等于各字段(field)大小之和?编译器将如何在内存中放置这些字段?ANSI C对结构体的内存布局有什么要求?而我们的程序又能否依赖这种布局?这些问题或许对不少朋友来说还有点模糊,那么本文就试着探究它们背后的秘密. 首先,至少有一点可以肯定,那就是ANSI C保证结构体中各字段在内存中出现的位置是随它们的声明顺序依次递增的,并且第一个字段的