结构体对齐

结构体对齐
结构体对齐

关于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{

chara;

structAb;

longc;

};

structC{

chara;

structAb;

doublec;

};

structD{

chara;

structAb;

doublec;

intd;

};

structE{

chara;

intb;

structAc;

doubled;

};

对于struct A 来说,对于char型数据,其自身对齐值为1,对于long类型,其自身对齐值为4, 结构体的自身对齐值取其成员最大的对齐值,即大小4。那么struct A 在内存中的顺序步骤为:

(1) char a, 地址范围为0x0000~0x0000,起始地址为0x0000,满足0x0000 % 1 = 0,这个成员字节对齐了。

(2) long b, 地址起始位置不能从0x00001开始,因为0x0001 % 4 != 0,所以先补空字节,直到0x00003结束,即补3个字节的空字节,从0x00004开始存放b,其地址范围为0x00004~0x0007.

(3)此时成员都存放结束,结构体长度为8,为结构体自身对齐值的2倍,符合条件

(二).

此时满足条件(一)和条件(二),struct A 中各成员在内存中的位置为:a*** b ,si zeof(struct A) = 8。(每个星号代表一位,成员各自代表自己所占的位,比如a占一位,b占四位)

对于struct B,里面有个类型为struct A的成员b自身对齐值为4,对于long类型,其自身对齐值为4. 故struct B的自身对齐值为4。那么structB 在内存中的顺序

步骤为:

(1) char a, 地址范围为0x0000~0x0000,起始地址为0x0000,满足0x0000 % 1 = 0,这个成员字节对齐了。

(2) struct A b, 地址起始位置不能从0x00001开始,因为0x0001 % 4 != 0,所以先补空字节,直到0x00003结束,即补3个字节的空字节,从0x00004开始存放b,其地址范围为0x00004~0x00011.

(3) long c,地址起始位置从0x000012开始,因为0x0012 % 4 = 0,其地

址范围为0x00012~0x0015.

(4)此时成员都存放结束,结构体长度为16,为结构体自身对齐值的4倍,符合条件

(二).

此时满足条件(一)和条件(二),struct B 中各成员在内存中的位置为:a*** b c , sizeof(struct C) = 24。(每个星号代表一位,成员各自代表自己所占的位,比如a占

一位,b占八位,c占四位)

对于struct C,里面有个类型为struct A的成员b自身对齐值为4,对于double

类型,其自身对齐值为8. 故struct C的自身对齐值为8。那么struct C 在内存中的顺序步骤为:

(1) char a, 地址范围为0x0000~0x0000,起始地址为0x0000,满足0x0000 % 1 = 0,这个成员字节对齐了。

(2) struct A b, 地址起始位置不能从0x00001开始,因为0x0001 % 4 != 0,所以先补空字节,直到0x00003结束,即补3个字节的空字节,从0x00004开始存放b,其地址范围为0x00004~0x00011.

(3) double c,地址起始位置不能从0x000012开始,因为0x0012 % 8 != 0,所以先补空字节,直到0x000015结束,即补4个字节的空字节,从0x00016开始存放c,其地址范围为0x00016~0x0023.

(4)此时成员都存放结束,结构体长度为24,为结构体自身对齐值的3倍,符合条件

(二).

此时满足条件(一)和条件(二),struct C 中各成员在内存中的位置为:a*** b ** ** c ,sizeof(struct C) = 24。(每个星号代表一位,成员各自代表自己所占的位,比

如a占一位,b占八位,c占八位)

对于struct D,自身对齐值为8。前面三个成员与struct C 是一致的。对于第四

成员d,因为0x0024 % 4 = 0, 所以可以从0x0024开始存放d, 其地址范围为0x 00024~0x00027.此时成员都存放结束,结构体长度为28,28 不是结构体自身对齐值

8的倍数,所以要在后面补四个空格,即在0x0028~0x0031上补四个空格。补完了,结构体长度为32, 为结构体自

身对齐值的4被,,符合条件(二).

此时满足条件(一)和条件(二),struct D 中各成员在内存中的位置为:a*** b ** ** c d **** ,sizeof(struct D) = 32。(每个星号代表一位,成员各自代表自己所占的位,比如a占一位,b占八位,c占八位, d占四位)。

对于struct E 中各成员在内存中的位置为:a*** b c d, sizeof(struct E) = 2 4。(每个星号代表一位,成员各自代表自己所占的位,比如a占一位,b占四位,c占八位, d占八位)。

通过struct D 和 struct E 可以看出,在成员数量和类型一致的情况,后者的所占空间少于前者,因为后者的填充空字节要少。如果我们在编程时考虑节约空间的话,应该遵循将变量按照类型大小从小到大声明的原则, 这样尽量减少填补空间。另外,可以在填充空字节的地方来插入reserved成员, 例如

struct A

{

char a;

char reserved[3];

int b;

};

这样做的目的主要是为了对程序员起一个提示作用,如果不加则编译器会自动补齐。

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];

C语言结构体和共用体实验报告

实验九参考程序 实验 9- 1 /**************************************************************** * 实验 9.1 * * ( 1 )为某商店的商品设计合适的结构体 (PRODUCT) 。每一种商品包含编号 (number) 、 * 名称 (name) 、价格 (price) 、折扣 (discount)4 项信息,根据表 9-1 ,为这些信 息选择合适的数据类型。 * (2)建立 2个函数,以实现对商品的操作。 input 函数实现商品的输入; * display 函数显示商品信息。要求这 2个函数都以商品的结构体 (PRODUCT) 指针为 参数。 * (3 )在主函数中为商品键盘定义一个结构体变量 (keyboard) ,利用 input 函数实现键 盘信息的输入; * 定义一个结构体数组 (elec_device[3]) ,利用 input 函数实现冰箱、 空调、电视 信息的输入; * 最后利用 display 函数显示 4 种商品的信息。 * * 表 9-1 #include typedef struct _PRODUCT int iNumber; char strName[32]; float fPrice; float fDiscount; * 编号 名称 价格 折扣 *1010 键盘 89.50 0.85 *1021 冰箱 1024.00 0.95 *1022 空调 2058.50 0.90 *1023 电视 3001.88 0.95 *************************************************************** */

C语言结构体共用体选择题新

1、变量 a 所占的内存字节数是。(假设整型int 为 4 字节) structstu {charname[20]; longintn; intscore[4]; }a; A)28B)30 C)32D)46 C 2、下列程序的输出结果是 A)5B)6 C)7D)8 structabc {inta,b,c;}; main() {structabcs[2]={{1,2,3},{4,5,6}};intt; t=s[0].a+s[1].b; printf("%d\n",t); } B 3、有如下定义 structperson{charname[9];intage;}; structpersoncalss[4]={"Johu",17, "Paul",19, "Mary",18, "Adam",16,}; 根据以上定义,能输出字母M 的语句是________ 。 A)printf("%c\n",class[3].name); B)printf("%c\n",class[3].name[1]); C)printf("%c\n",class[2].name[1]); D)printf("%c\n",class[2].name[0]); D 4、以下程序的输出是________ 。 structst {intx;int*y;}*p; intdt[4]={10,20,30,40}; structstaa[4]={50,&dt[0],60,&dt[0],60,&dt[0],60,dt[0],}; main() {p=aa; printf("%d\n",++(p->x)); } A)10B)11 C)51D)60 C 6、以下程序的输出结果是________ 。 structHAR {intx,y;structHAR*p;}h[2]; main() {inth[0].x=1;h[0].y=2; h[1].x=3;h[1].y=4;

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 占用内存如下图:

内存对齐方式

对齐方式 为什么会有内存对齐? 在结构中,编译器为结构的每个成员按其自然对界(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 语言中的结构体对齐 (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{

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。

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语言结构体与共用体之间的区别

https://www.360docs.net/doc/f015238681.html,/2005/03/25/12365.html 所谓共用体类型是指将不同的数据项组织成一个整体,它们在内存中占用同一段存储单元。其定义形式为: union 共用体名 {成员表列}; 7.5.1 共用体的定义 union data { int a ; float b ; d o u b l e c ; c h a r d ; } obj; 该形式定义了一个共用体数据类型union data ,定义了共用体数据类型变量o b j。共用体 数据类型与结构体在形式上非常相似,但其表示的含义及存储是完全不同的。先让我们看一个小例子。 [例7 - 8 ] union data /*共用体* / { int a; float b; double c; char d; } m m ; struct stud /*结构体* / { int a; float b; double c; char d; } ; m a i n ( ) { struct stud student printf("%d,%d",sizeof(struct stud),sizeof(union data)); } 程序的输出说明结构体类型所占的内存空间为其各成员所占存储空间之和。而形同结构体的

共用体类型实际占用存储空间为其最长的成员所占的存储空间。详细说明如图7 - 6所示。 对共用体的成员的引用与结构体成员的引用相同。但由于共用体各成员共用同一段内存 空间,使用时,根据需要使用其中的某一个成员。从图中特别说明了共用体的特点,方便程序设计人员在同一内存区对不同数据类型的交替使用,增加灵活性,节省内存。 7.5.2 共用体变量的引用 可以引用共用体变量的成员,其用法与结构体完全相同。若定义共用体类型为: union data /*共用体* / { int a; float b; double c; char d; } m m ; 其成员引用为:m m . a , m m . b , m m . c , m m . d 但是要注意的是,不能同时引用四个成员,在某一时刻,只能使用其中之一的成员。 [例7-9] 对共用体变量的使用。 m a i n ( ) { union data { int a; float b; double c; char d; } m m ; m m . a = 6 ; printf("%d\n",mm.a); m m . c = 6 7 . 2 ; p r i n t f ( " % 5 . 1 l f \ n " , m m . c ) ; m m . d = ' W ' ; m m . b = 3 4 . 2 ; p r i n t f ( " % 5 . 1 f , % c \ n " , m m . b , m m . 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,

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语言结构体共用体选择题新

c语言结构体共用体选择 题新 The pony was revised in January 2021

1、变量a所占的内存字节数是________。(假设整型i n t为4字节) struct stu { char name[20]; long int n; int score[4]; } a ; A) 28 B) 30 C) 32 D) 46 C 2、下列程序的输出结果是 A)5 B)6 C)7 D)8 struct abc {int a,b,c;}; main() {struct abc s[2]={{1,2,3},{4,5,6}};int t;

t=s[0].a+s[1].b; printf("%d\n",t); } B 3、有如下定义 struct person{ char name[9]; int age;}; struct person calss[4]={ "Johu",17, "Paul",19, "Mary",18, "Adam",16,}; 根据以上定义,能输出字母M的语句是________。 A) printf("%c\n",class[3].name); B) printf("%c\n",class[3].name[1]); C) printf("%c\n",class[2].name[1]); D) printf("%c\n",class[2].name[0]);

D 4、以下程序的输出是________。 struct st {int x;int *y;} *p; int dt[4]={10,20,30,40}; struct st aa[4]={50,&dt[0],60,&dt[0],60,&dt[0],60,dt[0],}; main() { p=aa; printf("%d\n",++(p->x)); } A) 10 B) 11 C) 51 D) 60 C 6、以下程序的输出结果是________。 struct HAR

结构体对齐方式

结构体对齐方式 结构体(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语言内存字节对齐规则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

C语言程序设计 结构体与共用体

页眉内容 一、选择题 1、定义结构类型时,下列叙述正确的是() A、系统会按成员大小分配每个空间 B、系统会按最大成员大小分配空间 C、系统不会分配空间 D、以上说法均不正确 2、已知结构类型变量x的初始化值为{“20”,30,40,35.5},请问合适的结构定义是() A、Struct s{int no;int x,y,z}; B、Struct s{char no[2];int x,y,z}; C、Struct s{int no;float x,y,z}; D、Struct s{char no[2];float x,y,z}; 3、若程序中有定义struct abc{int x;char y;};abc s1,s2;则会发生的情况是() A、编译时会有错误 B、链接时会有错误 C、运行时会有错误 D、程序没有错误 4、已知学生记录描述为 struct student {int no; char name[20]; char set; struct {int year; int month; int day; }birth;}; struct student s; 设变量s中的“生日”应是“1984年11月11日”,下列对生日的正确赋值方式是( ). A)year=1984; B)birth.year=1984; month=11; birth.month=11; day=11; birth.day=11; C)s.year=1984; D)s.birth.year=1984; s.month=11; s.birth.month=11; s.day=11; s.birth.day=11; 5、当说明一个结构体变量时系统分配给它的内存是( ). A)各成员所需内存量的总和 B)结构中第一个成员所需内存量 C)成员中占内存量最大者所需的容量 D)结构中最后一个成员所需内存量 6、以下对结构体类型变量的定义中不正确的是( ). A)#define STUDENT struct student B)struct student STUDENT {int num; {int num; float age; float age; }std1; }std1; C)struct D)struct {int num; int num;

相关文档
最新文档