结构体所占内存大小(字节对齐问题)

结构体所占内存大小(字节对齐问题)
结构体所占内存大小(字节对齐问题)

C语言中结构体占用内存大小的问题

2014-04-22 10:55 Deng_Ran | 分类:C/C++ | 浏览381次

struct stOne // 结构体1

{

char c1;

int i1;

char c2;

int i2;

};

struct stTwo // 结构体2

{

char c1;

char c2;

int i1;

int i2;

};

各位大侠,上面两个结构体因为硬件的边界调整原则,占用内存大小并不相同。在我的电脑上,sizeof(struct stOne)是16,sizeof(struct stTwo)是12。

小弟有一疑问,会不会存在一种情况:

struct stOne stA, stB; // 定义两个结构体

这两个结构体大小并不相同,即同一类型结构体能否占用不同内存大小?

分享到:

2014-04-22 11:01 提问者采纳

你好,struct stOne stA, stB; // 定义两个结构体

这两个结构体大小完全相同!!

追问

谢谢大侠回复,小弟还有一问题请教:

struct stOne

{

char c1;

int i1;

char c2;

};

char类型变量的边界是1,int类型变量的边界是4,那么,我感觉这个结构体的大小是1 + (3) + 4 + 1 = 9,但实际上占用的内存是12?

回答

是的,最后的大小就类似于一个由几根木板组成的长方形,也许每根的长度都不一样,但是都要按照最长的那根那样存放,所以占用内存= 最长的那根 X 根数

有3个变量所以 4*3 =12

其他3条回答

2014-04-22 11:03 阳顶天鹿鼎记 | 七级

不会,同一个结构体占用的内存都是一样的,

stOne和stTwo之所以不同,是因为内存对齐问题。

取内存时,是按照主机系统是多少位来取的

32位系统,每次取四个字节

64位系统,每次取8个字节

根据你sizeof得到的结果,你的系统是32位的,所以每次取四个字节,而stOne char类型占用一个,而int占用四个,所以char类型自动占用了4个,否则,如果char占用一个,取得时候,去了一个char,然后去了int变量的前三个,这样会出问题,所以,会得到你上面sizeof的结果

stTwo,就不会因为是两个char类型挨着的,这样两个char类型占用四个,取得时候先取两个char,再取int。

评论 | 3 0

2014-04-22 11:04 冰血无双 | 七级

不会不同,自己查一下数据补齐、数据对齐,还有内存页的概念

评论 | 1 0

2014-04-22 11:05 ylx2193395 | 三级

这是因为字节对齐原则,在Linux下其是按2字节对齐,可是在VC++下默认是按8字节对齐,必须满足4的整数倍。这样有助于存储效率。第一个char 为1字节,int为4字节,由于8字节对齐原则系统会预留出3个字节,保证8个字节对齐。而第二个两个char 2个字节,1个int4字节,系统补充2个字节后,此时8个字节,再加一个Int为12.满足条件

sizeof进行结构体大小的判断

sizeof进行结构体大小的判断 typedef struct { int a; char b; }A_t; typedef struct { int a; char b; char c; }B_t; typedef struct { char a; int b; char c; }C_t; void main() { char*a=0; cout<

2. 语法: sizeof有三种语法形式,如下: 1) sizeof( object ); // sizeof( 对象); 2) sizeof( type_name ); // sizeof( 类型); 3) sizeof object; // sizeof 对象; 5. 指针变量的sizeof 既然是来存放地址的,那么它当然等于计算机内部地址总线的宽度。所以在32位计算机中,一 个指针变量的返回值必定是4(以字节为单位),可以预计,在将来的64位系统中指针变量的sizeof结果为8。 char* pc = "abc"; int* pi; string* ps; char** ppc = &pc; void (*pf)();// 函数指针 sizeof( pc ); // 结果为4 sizeof( pi ); // 结果为4 sizeof( ps ); // 结果为4 sizeof( ppc ); // 结果为4 sizeof( pf );// 结果为4 指针变量的sizeof值与指针所指的对象没有任何关系,正是由于所有的指针变量所占内存大小相等,所以MFC消息处理函数使用两个参数WPARAM、LPARAM 就能传递各种复杂的消息结构(使用指向结构体的指针)。 6. 数组的sizeof 数组的sizeof值等于数组所占用的内存字节数,如: char a1[] = "abc"; int a2[3];

内存对齐方式

对齐方式 为什么会有内存对齐? 在结构中,编译器为结构的每个成员按其自然对界(alignment)条件分配空间;各个成员按照它们被声明的顺序在内存中顺序存储,第一个成员的地址和整个结构的地址相同。在缺省情况下,C编译器为每一个变量或数据单元按其自然对界条件分配空间。 字,双字,和四字在自然边界上不需要在内存中对齐。(对字,双字,和四字来说,自然边界分别是偶数地址,可以被4整除的地址,和可以被8整除的地址。)无论如何,为了提高程序的性能,数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;然而,对齐的内存访问仅需要一次访问。 一个字或双字操作数跨越了4字节边界,或者一个四字操作数跨越了8字节边界,被认为是未对齐的,从而需要两次总线周期来访问内存。一个字起始地址是奇数但却没有跨越字边界被认为是对齐的,能够在一个总线周期中被访问。 某些操作双四字的指令需要内存操作数在自然边界上对齐。如果操作数没有对齐,这些指令将会产生一个通用保护异常(#GP)。双四字的自然边界是能够被16整除的地址。其他的操作双四字的指令允许未对齐的访问(不会产生通用保护异常),然而,需要额外的内存总线周期来访问内存中未对齐的数据。 影响结构体的sizeof的因素: 1)不同的系统(如32位或16位系统):不同的系统下int等类型的长度是变化的,如对于16位系统,int的长度(字节)为2,而在32位系统下,int的长度为4;因此如果结构体中有int等类型的成员,在不同的系统中得到的sizeof值是不相同的。 2)编译器设置中的对齐方式:对齐方式的作用常常会让我们对结构体的sizeof 值感到惊讶,编译器默认都是8字节对齐。 对齐: 为了能使CPU对变量进行高效快速的访问,变量的起始地址应该具有某些特性,即所谓的“对齐”。例如对于4字节的int类型变量,其起始地址应位于4字节边界上,即起始地址能够被4整除。变量的对齐规则如下(32位系统)

C 语言中 地址对齐与数据对齐

------------------------------Editor: JaceLin-----------------Date: 2014.2.7--------------------------- C语言中的地址&数据对齐 NOTE: 在单片机开发中,不论是什么样的单片机,打开官方头文件都会发现,里面全是各种各样的结构体(struct)与宏定义(define),但不论定义的字母多么长多么难懂,它们的最终映像都是一个16进制的地址。对于一个单片机初学者来说,看到这些定义往往会很头痛,因为平时基本都是用别人的头文件,很少去写自己的单片机头文件。 前几天一直在写一个freescal K60单片机DMA程序,DMA就是‘直接对寄存器存取’,顾名思义,这个程序要涉及寄存器的操作(其实所有的单片机程序都是操作寄存器,只是定义了宏不直观而已)!DMA对于我来说第一次接触,中间就接触到了许多关于前面所说的官方给的struct与define,但是我感觉他们写的都很啰嗦过于繁琐,于是为了简化程序,我不得不弄清楚这些定义到底是什么意思。我专门去网上找了很多关于这方面的资料,最后我得出结论,其实就是两个方面内容:地址对齐与数据对齐! 下面就让我来解读这些难懂的struct & define. 一、数据对齐(以下内容都以32bit x86/arm平台为例) 在没有#progma pack(n)参数的情况下: 例1: struct A{ char a; char b; char c; }; Sixeof(struct A) =多少? 分析:一个char 长度为1个字节,而内存单元为4个字节,以上struct A 占用内存如下图:

结构体对齐

关于 C 语言中的结构体对齐 (1)什么是字节对齐 一个变量占用 n 个字节,则该变量的起始地址必须能够被n 整除,即: 存放起始地址 % n = 0 ,对于结构体而言,这个 n 取其成员种的数据类型占空间的值最大的那个。 (2)为什么要字节对齐 内存空间是按照字节来划分的,从理论上说对内存空间的访问可以从任何地址开始,但是在实际上不同架构的 CPU 为了提高访问内存的速度,就规定了对于某些类型的数据只能从特定的起始位置开始访问。这样就决定了各种数据类型只能按照相应的规则在内存空间中存放,而不能一个接一个的顺序排列。 举个例子,比如有些平台访问内存地址都从偶数地址开始,对于一个 int 型( 假设 32 位系统 ),如果从偶数地址开始的地方存放,这样一个读周期就可以读出这个 int 数据,但是如果从奇数地址开始的地址存放,就需要两个读周期,并对两次读出的结果的高低字节进行拼凑才能得到这个 int 数据,这样明显降低了读取的效率。 (3)如何进行字节对齐 每个成员按其类型的对齐参数 (通常是这个类型的大小 )和指定对齐参数 ( 不指定则取默认值 ) 中较小的一个对齐,并且结构的长度必须为所用过的所有对齐参数的整数倍 ,不够就补空字节。 这个规则有点苦涩,可以把这个规则分解一下,前半句的意思先获得对齐值后与指定对齐值进行比较 ,其中对齐值获得方式如下:

1. 数据类型的自身对齐值为:对于 char 型数据,其自身对齐值为 1 ,对于 short 型为 2 ,对于 int, long, float 类型,其自身对齐值为 4 ,对于 double 类型其自身对齐值为 8 ,单位为字节。 2. 结构体自身对齐值:其成员中自身对齐值最大的那个值。 其中指定对齐值获得方式如下: #pragma pack (value) 时的指定对齐值 value 。 未指定则取默认值。 后半句的意思是主要是针对于结构体的长度而言,因为针对数据类型的成员,它仅有一个对齐参数,其本身的长度、于这个对齐参数,即 1 倍。对于结构体而言,它可能使用了多种数据类型,那么这句话翻译成对齐规则:每个成员的起始地址 % 自身对齐值 = 0 ,如果不等于0 则先补空字节直至这个表达式成立。 换句话说,对于结构体而言,结构体在在内存的存放顺序用如下规则即可映射出来: ( 一)每个成员的起始地址 % 每个成员的自身对齐值 = 0 ,如果不等于 0 则先补空字节直至这个表达式成立; ( 二 ) 结构体的长度必须为结构体的自身对齐值的整数倍, 不够就补空字节。 举个例子: #pragmapack(8) structA{ chara; longb; }; structB{

字节对齐

字节对齐 Andrew Huang 内容提要 ●字节对齐概念 ●字节对齐测试 ?offsetof ?缺省情况的字节对齐 ?double 型字节对齐 ?改变字节对齐设置 ●不同环境下的字节对齐 ?GCC字节对齐 ?ADS 字节对齐 ●字节对齐练习 字节对齐是一个很隐含的概念,平时可能你没有留意,但是如果你在编写网络通讯程序或者用结构去操作文件或硬件通讯结构,这个问题就会浮出水面。我记得第一次导致我去看字节对齐概念资料的原因就是ARP通讯,ARP包头是一个31Byte包头。当你用一个认为是31Byte结构去处理数据包时,却总是处理不对。这一篇文章详细讨论了字节对齐要领和各种情况. 字节对齐概念 ●现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但为了CPU访问数据的快速,通常都要求数据存放的地址是有一定规律的. ●比如在32位CPU上,一般要求变量地址都是基于4位,这样可以保证CPU用一次的读写周期就可以读取变量.不按4位对齐,如果变量刚好跨4位编码,这样需要CPU两个读写周期.效率自然低下.因此,在现代的编译器都会自动把复合数据定义按4位对齐,以保证CPU以最快速度读取,这就是字节对齐(byte Alignment)产生的背景 ●字节对齐是一种典型,以空间换时间的策略的,在现代计算机拥有较大的内存的情况,这个策略是相当成功的. 为什么要字节对齐? ●加快程序访问速度 ●很多CPU对访问地址有严格要求,这时编译器必须要这个CPU的规范来实现,X86较为宽松,不对齐结构可能只 影响效率,如ARM,访问地址必须基于偶地址,MIPS和Sparc也类似,这样不对齐的地址访问会造成错误. 关于字节对齐的实现 在不同的CPU对地址对齐有不同要求,各个编译器也会采用不同策略来实现字节对齐,在随后的例子,可以对比PC下的Windows,和Linux,以有ARM下的字节对齐策略.

c++中关于结构体长度的计算问题

[C++]字节对齐与结构体大小 [C++] 2010-09-24 21:40:26 阅读172 评论0 字号:大中小订阅 说明: 结构体的sizeof值,并不是简单的将其中各元素所占字节相加,而是要考虑到存储空间的字节对齐问题。这些问题在平时编程的时候也确实不怎么用到,但在一些笔试面试题目中出是常常出现,对sizeof我们将在另一篇文章中总结,这篇文章我们只总结结构体的sizeof,报着不到黄河心不死的决心,终于完成了总结,也算是小有收获,拿出来于大家分享,如果有什么错误或者没有理解透的地方还望能得到提点,也不至于误导他人。 一、解释 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。 各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取。比如

有些架构的CPU在访问一个没有进行对齐的变量的时候会发生错误,那么在这种架构下编程必须保证字节对齐.其他平台可能没有这种情况,但是最常见的是如果不按照适合其平台要求对数据存放进行对齐,会在存取效率上带来损失。比如有些平台每次读都是从偶地址开始,如果一个int 型(假设为32位系统)如果存放在偶地址开始的地方,那么一个读周期就可以读出这32bit,而如果存放在奇地址开始的地方,就需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该32bit数据。 二、准则 其实字节对齐的细节和具体编译器实现相关,但一般而言,满足三个准则: 1. 结构体变量的首地址能够被其最宽基本类型成员的大小所整除; 2. 结构体每个成员相对于结构体首地址的偏移量都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节; 3. 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节。 三、基本概念

内存字节对齐

1.内存字节对齐和小端模式: /* 本程序是关于:编译器内存的字节对齐方式和存储时的小端对齐模式(win7 32bit) #pragma pack(n) 默认为8字节对齐,(即n=8)其中n的取值为1,2,4,8,16,32等 内存字节对齐大小和方式: 1)结构体内变量对齐: 每个变量的对齐字节数大小argAlignsize=min(#pragma pack(n),sizeof(变量)); 方式:结构体的第一个变量的初始偏移地址为0,其它变量的偏移地址(当前变量的起始地址)必须是argAlignsize的整数倍,不够整数倍的补空,不添加任何数据 2)结构体对齐: 结构体的对齐字节数大小strAlignsize=min(#pragma pack(n),sizeof(所有变量中最大字节的变量)) 方式: A.对于单独的结构体来说,结构体本身按照strAlignsize大小来对齐 B.结构体B在结构体A中时,结构体B的起始地址是结构体B的 strAlignsize大小的整数倍 小端对齐模式: 指针指着一个存储空间,存储空间地址由低到高的存储内容为:0x78,0x67,0x33,0x45 若指针为char,则获取的数据为0x78 若指针为short,则获取的数据为0x6778 若指针为long,则获取的数据为0x45336778 */ #include using namespace std; /*更改C编译器内存的缺省字节对齐方式,由默认的n=4字节,变为n字节对齐,其中n的取值为1,2,4,8,16,32等*/ #pragma pack(2) struct A { unsigned char a; unsigned short b; }; struct B { unsigned char c; unsigned int d;

C语言内存对齐

解析C语言结构体对齐(内存对齐问题) C语言结构体对齐也是老生常谈的话题了。基本上是面试题的必考题。内容虽然很基础,但一不小心就会弄错。写出一个struct,然后sizeof,你会不会经常对结果感到奇怪?sizeof的结果往往都比你声明的变量总长度要大,这是怎么回事呢? 开始学的时候,也被此类问题困扰很久。其实相关的文章很多,感觉说清楚的不多。结构体到底怎样对齐? 有人给对齐原则做过总结,具体在哪里看到现在已记不起来,这里引用一下前人的经验(在没有#pragma pack宏的情况下): 原则1、数据成员对齐规则:结构(struct或联合union)的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小的整数倍开始(比如int在32位机为4字节,则要从4的整数倍地址开始存储)。 原则2、结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储。(struct a里存有struct b,b里有char,int,double等元素,那b应该从8的整数倍开始存储。) 原则3、收尾工作:结构体的总大小,也就是sizeof的结果,必须是其内部最大成员的整数倍,不足的要补齐。 这三个原则具体怎样理解呢?我们看下面几个例子,通过实例来加深理解。 例1:struct { short a1; short a2; short a3; }A; struct{ long a1; short a2; }B; sizeof(A) = 6; 这个很好理解,三个short都为2。 sizeof(B) = 8; 这个比是不是比预想的大2个字节?long为4,short为2,整个为8,因为原则3。 例2:struct A{ int a; char b; short c; }; struct B{ char b; int a; short c; }; sizeof(A) = 8; int为4,char为1,short为2,这里用到了原则1和原则3。 sizeof(B) = 12; 是否超出预想范围?char为1,int为4,short为2,怎么会是12?还是原则1和原则3。

stm32中使用#pragma pack(非常有用的字节对齐用法说明)

#pragma pack(4) //按4字节对齐,但实际上由于结构体中单个成员的最大占用字节数为2字节,因此实际还是按2字节对齐 typedef struct { char buf[3];//buf[1]按1字节对齐,buf[2]按1字节对齐,由于buf[3]的下一成员word a是按两字节对齐,因此buf[3]按1字节对齐后,后面只需补一空字节 word a; //#pragma pack(4),取小值为2,按2字节对齐。 }kk; #pragma pack() //取消自定义字节对齐方式 对齐的原则是min(sizeof(word ),4)=2,因此是2字节对齐,而不是我们认为的4字节对齐。 这里有三点很重要: 1.每个成员分别按自己的方式对齐,并能最小化长度 2.复杂类型(如结构)的默认对齐方式是它最长的成员的对齐方式,这样在成员是复杂类型时,可以最小化长度 3.对齐后的结构体整体长度必须是成员中最大的对齐参数的整数倍,这样在处理数组时可以保证每一项都边界对齐 补充一下,对于数组,比如: char a[3];这种,它的对齐方式和分别写3个char是一样的.也就是说它还是按1个字节对齐. 如果写: typedef char Array3[3]; Array3这种类型的对齐方式还是按1个字节对齐,而不是按它的长度. 不论类型是什么,对齐的边界一定是1,2,4,8,16,32,64....中的一个. 声明: 整理自网络达人们的帖子,部分参照MSDN。 作用: 指定结构体、联合以及类成员的packing alignment; 语法: #pragma pack( [show] | [push | pop] [, identifier], n ) 说明: 1,pack提供数据声明级别的控制,对定义不起作用; 2,调用pack时不指定参数,n将被设成默认值; 3,一旦改变数据类型的alignment,直接效果就是占用memory的减少,但是performance会下降; 语法具体分析: 1,show:可选参数;显示当前packing aligment的字节数,以warning message的形式被显示; 2,push:可选参数;将当前指定的packing alignment数值进行压栈操作,这里的栈是the internal compiler stack,同时设置当前的packing alignment为n;如果n没有指定,则将当前的packing alignment数值压栈; 3,pop:可选参数;从internal compiler stack中删除最顶端的record;如果没有指定n,则当前栈顶record即为新的packing alignment 数值;如果指定了n,则n将成为新的packing aligment数值;如果指定了identifier,则internal compiler stack中的record都将被pop 直到identifier被找到,然后pop出identitier,同时设置packing alignment数值为当前栈顶的record;如果指定的identifier并不存在于internal compiler stack,则pop操作被忽略; 4,identifier:可选参数;当同push一起使用时,赋予当前被压入栈中的record一个名称;当同pop一起使用时,从internal compiler stack 中pop出所有的record直到identifier被pop出,如果identifier没有被找到,则忽略pop操作; 5,n:可选参数;指定packing的数值,以字节为单位;缺省数值是8,合法的数值分别是1、2、4、8、16。 重要规则: 1,复杂类型中各个成员按照它们被声明的顺序在内存中顺序存储,第一个成员的地址和整个类型的地址相同; 2,每个成员分别对齐,即每个成员按自己的方式对齐,并最小化长度;规则就是每个成员按其类型的对齐参数(通常是这个类型的大小)和指定对齐参数中较小的一个对齐; 3,结构体、联合体或者类的数据成员,第一个放在偏移为0的地方;以后每个数据成员的对齐,按照#pragma pack指定的数值和这个数据成员自身长度两个中比较小的那个进行;也就是说,当#pragma pack指定的值等于或者超过所有数据成员长度的时候,这个指定值的大小将不产生任何效果; 4,复杂类型(如结构体)整体的对齐是按照结构体中长度最大的数据成员和#pragma pack指定值之间较小的那个值进行;这样当数据成员为复杂类型(如结构体)时,可以最小化长度; 5,复杂类型(如结构体)整体长度的计算必须取所用过的所有对齐参数的整数倍,不够补空字节;也就是取所用过的所有对齐参数中最大的那个值的整数倍,因为对齐参数都是2的n次方;这样在处理数组时可以保证每一项都边界对齐; 对齐的算法:由于各个平台和编译器的不同,现以本人使用的gcc version 3.2.2编译器(32位x86平台)为例子,来讨论编译器对struct 数据结构中的各成员如何进行对齐的。 在相同的对齐方式下,结构体内部数据定义的顺序不同,结构体整体占据内存空间也不同,如下: 设结构体如下定义: struct A { int a; //a的自身对齐值为4,偏移地址为0x00~0x03,a的起始地址0x00满足0x00%4=0;

C语言结构体的字节对齐及指定对齐方式

内存中结构体的内存对齐 一、字节对齐作用和原因: 对齐的作用和原因:各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取。比如有些架构的CPU在访问一个没有进行对齐的变量的时候会发生错误,那么在这种架构下编程必须保证字节对齐,其他平台可能没有这种情况,但是最常见的是如果不按照适合其平台要求对数据存放进行对齐,会在存取效率上带来损失。比如有些平台每次读都是从偶地址开始,如果一个int型(假设为32位系统)如果存放在偶地址开始的地方,那么一个读周期就可以读出这32bit,而如果存放在奇地址开始的地方,就需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该32bit 数据,显然在读取效率上下降很多。 二、字节对齐规则: 四个重要的概念: 1.数据类型自身的对齐值:对于char型的数据,其自身对齐值为1,对于short型为2,对于int,float,double类型,其自身对齐值为4个字节。 2.结构体或者类的自身对齐值:其成员中自身对齐值最大的那个值。 3.指定对齐值:#pragma pack (value)时指定的对齐value。 4.数据成员、结构体和类的有效对齐值:自身对齐值和指定对齐值中小的那个值。补充: 1).每个成员分别按自己的方式对齐,并能最小化长度。 2).复杂类型(如结构)的默认对齐方式是它最长的成员的对齐方式,这样在成员是复杂类型时,可以最小化长度。 3).对齐后的长度必须是成员中最大的对齐参数的整数倍,这样在处理数组时可以保证每一项都边界对齐。 #pragma pack(1) struct test { static int a; //static var double m4; char m1; int m3; } #pragma pack() //sizeof(test)=13;

C语言内存字节对齐规则20180718

C语言内存字节对齐规则 在C语言面试和考试中经常会遇到内存字节对齐的问题。今天就来对字节对齐的知识进行小结一下。 首先说说为什么要对齐。为了提高效率,计算机从内存中取数据是按照一个固定长度的。以32位机为例,它每次取32个位,也就是4个字节(每字节8个位,计算机基础知识,别说不知道)。字节对齐有什么好处?以int型数据为例,如果它在内存中存放的位置按4字节对齐,也就是说1个int的数据全部落在计算机一次取数的区间内,那么只需要取一次就可以了。如图a-1。如果不对齐,很不巧,这个int数据刚好跨越了取数的边界,这样就需要取两次才能把这个int的数据全部取到,这样效率也就降低了。 图:a-1 图:a-2 内存对齐是会浪费一些空间的。但是这种空间上得浪费却可以减少取数的时间。这是典型的一种以空间换时间的做法。空间与时间孰优孰略这个每个人都有自己的看法,但是C 语言既然采取了这种以空间换时间的策略,就必然有它的道理。况且,在存储器越来越便宜的今天,这一点点的空间上的浪费就不算什么了。 需要说明的是,字节对齐不同的编译器可能会采用不同的优化策略,以下以GCC为例讲解结构体的对齐. 一、原则: 1.结构体内成员按自身按自身长度自对齐。

自身长度,如char=1,short=2,int=4,double=8,。所谓自对齐,指的是该成员的起始位置的内存地址必须是它自身长度的整数倍。如int只能以0,4,8这类的地址开始 2.结构体的总大小为结构体的有效对齐值的整数倍 结构体的有效对齐值的确定: 1)当未明确指定时,以结构体中最长的成员的长度为其有效值 2)当用#pragma pack(n)指定时,以n和结构体中最长的成员的长度中较小者为其值。 3)当用__attribute__ ((__packed__))指定长度时,强制按照此值为结构体的有效对齐值 二、例子 1) struct AA{ //结构体的有效对齐值为其中最大的成员即int的长度4 char a; int b; char c; }aa 结果,sizeof(aa)=12 何解?首先假设结构体内存起始地址为0,那么地址的分布如下 0 a 1 2 3 4 b 5 b 6 b 7 b 8 c 9 10 11 char的字对齐长度为1,所以可以在任何地址开始,但是,int自对齐长度为4,必须以4的倍数地址开始。所以,尽管1-3空着,但b也只能从4开始。再加上c后,整个结构体的总长度为9,结构体的有效对齐值为其中最大的成员即int的长度4,所以,结构体的大小向上扩展到12,即9-11的地址空着。 2) //结构体的有效对齐值为其中最大的成员即int的长度4 struct AA{ char a; char c; int b; }aa sizeof(aa)=8,为什么呢 0 a 1 c

经验技巧8-1 结构体变量的存储长度

经验技巧8-1 结构体变量的存储长度 结构体变量的存储长度,跟编译器字节对齐密切相关。为了使CPU对变量进行快速高效的访问,变量的起始地址应该满足某些特性,即所谓的对齐。关于字节对齐有两个重要的宏:#pragma pack (n)和#pragma pack。 (1)#pragma pack (n):一般情况下,此宏的作用在于强制编译器以n的倍数进行地址对齐。 (2)#pragma pack:结束前面设置的对齐方式,恢复到编译器默认的对齐方式。 Visual C++默认的字节对齐数为8。 结构体变量中的成员item在结构体中相对于首地址的偏移量应该是X的倍数,X由如下式决定: X=min(n,sizeof(item)),(item是占字节最大的类型的成员) 【示例1】假设n为8,若有如下定义 struct Test { char c1; char c2; int i;}; struct Test t; 那么在存储结构体变量t的成员i时,X就应该是min(8,sizeof(int))=4的倍数,即i相对于结构体变量首地址的偏移量必须是4的倍数,所以t的大小就应该为8=(2+2+4)字节(在c1和c2后填充了两个字节以满足前述条件)。 而对于struct { char c1; char c2} t;则不会出现填充的的情况,每个成员相对首地址的偏移量也满足是X的倍数(此时X为1),变量t的大小为2字节。 【示例2】若有结构体变量:struct {char c1; double d;} t;,默认情况下结构体变量t占用16=(8+8)字节(在c1后填充7个字节以满足字节对齐)。如果强制编译器以4字节对齐,即在声明这种结构体变量前有宏定义#pragma pack (4),此时X为4,则此种类型结构体变量占用的内存为12=(4+8)字节。 还有一种特殊情况,就是空结构体。在Visual C++下其大小为1,即struct{}类型的变量在VC下输出其大小是1,原因就是VC为每个结构体变量分配一个字节的内存,以使该变量有个地址;而在gcc下输出其大小为0。 最后,结构体成员中有结构体变量的情况见下例: 【示例3】若有struct test1 { char c1; int i ; char c2 ;}t1;则X=4,所以t1占用4+4+4=12个字节,那么对于struct test2 { int i; struct test1 t1; char c2; }t2;有X=min{8,max(4,4,1)}=4,所以t2占用4+12+4=20个字节,在确定上述的X时会把t1拆散成基本数据类型来处理,而计算结构体变量t2的大小时又会把t1作为一个整体来对待。故默认情况下,结构体test2类型变量的大小为:20字节。

C语言结构体对齐

C语言结构体对齐 C语言结构体对齐也是老生常谈的话题了。基本上是面试题的必考题。内容虽然很基础,但一不小心就会弄错。写出一个struct,然后sizeof,你会不会经常对结果感到奇怪?sizeof的结果往往都比你声明的变量总长度要大,这是怎么回事呢? 开始学的时候,也被此类问题困扰很久。其实相关的文章很多,感觉说清楚的不多。结构体到底怎样对齐? 有人给对齐原则做过总结,具体在哪里看到现在已记不起来,这里引用一下前人的经验(在没有#pragma pack宏的情况下): 原则1、数据成员对齐规则:结构(struct或联合union)的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小的整数倍开始(比如int在32位机为4字节,则要从4的整数倍地址开始存储)。 原则2、结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储。(struct a里存有struct b,b 里有char,int,double等元素,那b应该从8的整数倍开始存储。) 原则3、收尾工作:结构体的总大小,也就是sizeof的结果,必须是其内部最大成员的整数倍,不足的要补齐。 这三个原则具体怎样理解呢?我们看下面几个例子,通过实例来加深理解。 例1:struct { short a1; short a2; short a3; }A; struct{ long a1; short a2; }B; sizeof(A) = 6; 这个很好理解,三个short都为2。 sizeof(B) = 8; 这个比是不是比预想的大2个字节?long为4,short为2,

C语言字节对齐

定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐 对齐的作用和原因:各个硬件平台对存储空间的处理上有很大的不同一些平台对某些特定类型的数据只能从某些特定地址开始存取其他平台可能没有这种情况, 台的要求对数据存放进行对齐,会在存取效率上带来损失比如有些平台每次读都是从偶地址开始,如果数据显然在读取效率上下降很多这也是空间和时间的博弈 不需要考虑对齐问题编译器会替我们选择适合目标平台的对齐策略当然,我们也可以通知给编译器传递预编译指令而改变对指定数据的对齐方法 话,常常会对一些问题感到迷惑最常见的就是结果,出乎意料为此,我们需要对对齐算法所了解 数据结构中的各成员如何进行对齐的 型数据一个 字节但是因为编译器要对数据成员在空间上进行对齐现在把该结构体调整成员变量的顺序

8 7 ,单位字节 )数据类型自身的对齐值:就是上面交代的基本数据类型的自身对齐值 )结构体或者类的自身对齐值:其成员中自身对齐值最大的那个值 )数据成员、结构体和类的有效对齐值:自身对齐值和指定对齐值中较小的那个值 有了这些值,我们就可以很方便的来讨论具体数据结构的成员和其自身的对齐方式有效对齐值 最终用来决定数据存放地址方式的值,最重要有效对齐 而数据结构中的数据变量都是按定义的先后顺序来排放的第一个数据变量的数据结构的起始地址结构体的成员变量要对齐排放,结构体本身也要根据自身的有效对 结合下面例子理解)这样就不难理解上面的几个例子的值了

开始排放该例子中没有定义指定对齐值,在笔者环境下,该值默认为 第三个变量 内容再看数据结构 所占用故 的变量又 的八个字节所以

结构体对齐方式

结构体对齐方式 结构体(struct)的sizeof值,并不是简单的将其中各元素所占字节相加,而是要考虑到存储空间的字节对齐问题。先看下面定义的两个结构体. struct { char a; short b; char c; }S1; struct { char a; char b; short c; }S2; 分别用程序测试得出sizeof(S1)=6 , sizeof(S2)=4 可见,虽然两个结构体所含的元素相同,但因为其中存放的元素类型顺序不一样,所占字节也出现差异。这就是字节对齐原因。通过字节对齐,有助于加快计算机的取数速度,否则就得多花指令周期。 字节对齐原则: 结构体默认的字节对齐一般满足三个准则: 1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除; 2) 结构体每个成员相对于结构体首地址的偏移量(offset)都是成员自身大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal adding); 3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节(trailing padding)。 通过这三个原则,就不难理解上面两个struct的差异了. 对于struct S1, 为了使short变量满足字节对其准则(2), 即其存储位置相对于结构体首地址的offset是自身大小(short占2个字节)的整数倍,必须在字节a后面填充一个字节以对齐;再由准则(3),为了满足结构体总大小为short大小的整数倍,必须再在c后面填充一个字节。对于struct S2, 却不必如上所述的填充字节,因为其直接顺序存储已经满足对齐准则。 如果将上面两个结构体中的short都改为int(占4个字节), 那么会怎么样呢?程序得出sizeof(S1)=12, sizeof(S2)=8 利用上面的准则,也不难计算得出这样的结果。S1中在a后面填充3个字节、在c后面填充3个字节,这样一共12个字节;S2中在a、b顺序存储之后填充两个字节用以对其,这样一共就8个字节。 当然,在某些时候也可以设置字节对齐方式。这就需要使用 #pragma pack 。 #pragma pack(push) //压栈保存 #pragma pack(1)// 设置1字节对齐 struct { char a; short b; char c; }S1; #pragma pack(pop) // 恢复先前设置 如上所示,将对其方式设为1字节对齐,那么S1就不填充字节,sizeof为各元素所占字节之和即4。这一点在从外部2进制文件中读入struct大小的数据到struct中,是很有用的。 另外,还有如下的一种方式:

C语言结构体(struct)常见使用方法

C语言结构体(struct)常见使用方法 基本定义:结构体,通俗讲就像是打包封装,把一些有共同特征(比如同属于某一类事物的属性,往往是某种业务相关属性的聚合)的变量封装在内部,通过一定方法访问修改内部变量。 结构体定义: 第一种:只有结构体定义 [cpp]view plain copy 1.struct stuff{ 2.char job[20]; 3.int age; 4.float height; 5.}; 第二种:附加该结构体类型的“结构体变量”的初始化的结构体定义 [cpp]view plain copy 1.//直接带变量名Huqinwei 2.struct stuff{ 3.char job[20]; 4.int age; 5.float height; 6.}Huqinwei; 也许初期看不习惯容易困惑,其实这就相当于: [cpp]view plain copy 1.struct stuff{ 2.char job[20]; 3.int age;

4.float height; 5.}; 6.struct stuff Huqinwei; 第三种:如果该结构体你只用一个变量Huqinwei,而不再需要用 [cpp]view plain copy 1.struct stuff yourname; 去定义第二个变量。 那么,附加变量初始化的结构体定义还可进一步简化出第三种: [cpp]view plain copy 1.struct{ 2.char job[20]; 3.int age; 4.float height; 5.}Huqinwei; 把结构体名称去掉,这样更简洁,不过也不能定义其他同结构体变量了——至少我现在没掌握这种方法。 结构体变量及其内部成员变量的定义及访问: 绕口吧?要分清结构体变量和结构体内部成员变量的概念。 就像刚才的第二种提到的,结构体变量的声明可以用: [cpp]view plain copy 1.struct stuff yourname; 其成员变量的定义可以随声明进行: [cpp]view plain copy 1.struct stuff Huqinwei = {"manager",30,185}; 也可以考虑结构体之间的赋值: [cpp]view plain copy

C语言结构体对齐问题

C语言结构体对齐问题 1。几个结构体例子: struct{ short a1; short a2; short a3; }A; struct{ long a1; short a2; }B; sizeof( A)=6, sizeof( B)=8,为什么? 注:sizeof(short)=2,sizeof(long)=4 因为:“成员对齐有一个重要的条件,即每个成员按自己的方式对齐。其对齐的规则是,每个成员按其类型的对齐参数(通常是这个类型的大小)和指定对齐参数(这里默认是8字节)中较小的一个对齐。并且结构的长度必须为所用过的所有对齐参数的整数倍,不够就补空字节。”(引用) 结构体A中有3个short类型变量,各自以2字节对齐,结构体对齐参数按默认的8字节对齐,则a1,a2,a3都取2字节对齐,则sizeof(A)为6,其也是2的整数倍; B中a1为4字节对齐,a2为2字节对齐,结构体默认对齐参数为8,则a1取4字节对齐,a2取2字节对齐,结构体大小6字节,6不为4的整数倍,补空字节,增到8时,符合所有条件,则sizeof(B)为8; 可以设置成对齐的 #pragma pack(1) #pragma pack(push) #pragma pack(1) struct{

short a1; short a2; short a3; }A; struct{ long a1; short a2; }B; #pragma pack(pop) 结果为sizeof( A)=6,sizeof( B)=6 ************************ #pragma pack(8) struct S1{ char a; long b; }; struct S2 { char c; struct S1 d; long long e; }; #pragma pack() sizeof(S2)结果为24.

[C++]字节对齐与结构体大小

[C++]字节对齐与结构体大小 说明: 结构体的sizeof值,并不是简单的将其中各元素所占字节相加,而是要考虑到存储空间的字节对齐问题。这些问题在平时编程的时候也确实不怎么用到,但在一些笔试面试题目中出是常常出现,对sizeof我们将在另一篇文章中总结,这篇文章我们只总结结构体的sizeof,报着不到黄河心不死的决心,终于完成了总结,也算是小有收获,拿出来于大家分享,如果有什么错误或者没有理解透的地方还望能得到提点,也不至于误导他人。 别忘了这里https://www.360docs.net/doc/ae2152490.html,/blog/static/30203796201082494026399/ 一、解释 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。 各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取。比如有些架构的CPU在访问一个没有进行对齐的变量的时候会发生错误,那么在这种架构下编程必须保证字节对齐.其他平台可能没有这种情况,但是最常见的是如果不按照适合其平台要求对数据存放进行对齐,会在存取效率上带来损失。比如有些平台每次读都是从偶地址开始,如果一个int型(假设为32位系统)如果存放在偶地址开始的地方,那么一个读周期就可以读出这32bit,而如果存放在奇地址开始的地方,就需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该32bit数据。 二、准则 其实字节对齐的细节和具体编译器实现相关,但一般而言,满足三个准则: 1. 结构体变量的首地址能够被其最宽基本类型成员的大小所整除; 2. 结构体每个成员相对于结构体首地址的偏移量都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节; 3. 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节。 三、基本概念 字节对齐:计算机存储系统中以Byte为单位存储数据,不同数据类型所占的空间不同,如:整型(int)数据占4个字节,字符型(char)数据占一个字节,短整型(short)数据占两个字节,等等。计算机为了快速的读写数据,默认情况下将数据存放在某个地址的起始位置,如:整型数据(int)默认存储在地址能被4整除的起始位置,字符型数据(char)可以存放在任何地址位置(被1整除),短整型(short)数据存储

C语言字节对齐

什么是字节对齐,为什么要对齐 现代计算机中内存空间都是按照BYTE划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。 作用和原因: 各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取。比如有些架构的CPU在访问一个没有进行对齐的变量的时候会发生错误,那么在这种架构下编程必须保证字节对齐.其他平台可能没有这种情况,但是最常见的是如果不按照适合其平台要求对数据存放进行对齐,会在存取效率上带来损失。比如有些平台每次读都是从偶地址开始,如果一个int型(假设为32位系统)如果存放在偶地址开始的地方,那么一个读周期就可以读出这32bit,而如果存放在奇地址开始的地方,就需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该32bit数据。 以下内容节选自《Intel Architecture 32 Manual》。 字,双字,和四字在自然边界上不需要在内存中对齐。(对字,双字,和四字来说,自然边界分别是偶数地址,可以被4整除的地址,和可以被8整除的地址。) 无论如何,为了提高程序的性能,数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;然而,对齐的内存访问仅需要一次访问。 一个字或双字操作数跨越了4字节边界,或者一个四字操作数跨越了8字节边界,被认为是未对齐的,从而需要两次总线周期来访问内存。一个字起始地址是奇数但却没有跨越字边界被认为是对齐的,能够在一个总线周期中被访问。 某些操作双四字的指令需要内存操作数在自然边界上对齐。如果操作数没有对齐,这些指令将会产生一个通用保护异常(#GP)。双四字的自然边界是能够被16 整除的地址。其他的操作双四字的指令允许未对齐的访问(不会产生通用保护异常),然而,需要额外的内存总线周期来访问内存中未对齐的数据。 一次访问时,要么读0x01~0x04,要么读0x05~0x08…… 硬件不支持一次访问就读到0x02~0x05 举个例子,如果0x02~0x05存了一个int,读取这个int就需要先读0x01~0x04,留下0x02~0x04的内容,再读0x05~0x08,留下0x05的内容,两部分拼接起来才能得到那个int的值…… 读一个int就要两次内存访问,效率就低了…… 字节对齐要区分四个概念 1、基本数据类型的自身对齐值: 1字节:char型 2字节:short型

相关文档
最新文档