GCC下结构体内存对齐问题

GCC下结构体内存对齐问题
GCC下结构体内存对齐问题

引言:结构对齐的目的是为了加快CPU取数据时的速度,不同的编译器有不同的标准,有关于4字节对齐的,也有关于8字节对齐的,解题时需跟据环境具体分析。

环境:ubuntu10.10 gcc

判断结构大小,只需要注意两点即可:

1.分析结构成员:

小于4字节的结构成员,相对起始地址要在成员大小的倍数上

Char 1 char 类型可以从任何地址开始

Short 2 short 类型需要相对结构起始地址以2 的倍数处开始

Int 4

大于4 4 对齐如double 大小为8字节,只需按4字节对齐即可

2.整个结构要关于最大的成员大小对齐(不大于4)

如果结构最大的成员是short 那么结构的大小应是2 的倍数,(不足时在结构末尾补足)如果最大成员是int ,则应是4 的倍数。

如果是double ,则是4 的倍数。

为什么是4 的倍数?

这是GCC默认的对齐大小,可以修改。VC下应该默认是8。

测试,以下结构的大小是?

struct com

{

char c1; 1字节由下面的对齐知道占用了4 字节

long tt; 关于4 字节对齐占用了4 字节

int c9; 关于4 字节对齐占用了4 字节

short c3; 关于2 字节对齐占用了4 字节

double c4; 关于4字节对齐占用了8 字节

}; 4 的倍数,所以大小共24 字节。

struct T

{

char a;

double b;

};

struct TT

{

short a;

char b;

short aa;

};

struct A

char c;

double d;

short s;

char sf[5]; };

struct B

{

short s;

char sf[5];

char c;

double d; };

struct C

{

char c;

short s;

char sf[5];

double d; };

struct D

{

double d;

char sf[5];

short s;

char c; };

struct E

{

char c;

char sf[5];

double d;

short s; };

#include

struct A

{ //QT/Cfree下GCC下char c; //8byte 4

double d; //8byte 8

short s; //7byte 4

char sf[5];//2 4

}a1;

//24

struct B

{

short s; //7byte 2

char sf[5];//0 5

char c; //1byte 1

double d; //8byte 8

}a2;

//16

struct C

{

char c; //2byte 1

short s; //7byte

char sf[5];//7

double d; //8byte

}a3;

//24

struct D

{

double d; //13byte

char sf[5];//1

short s; //2byte

char c; //8byte

}a4;

int main()

{

/* a.c='a';

a.d=5.2356;

a.s=3;

// a.sf[5]="xuwe";不能这样赋值*/

printf("%d\n",sizeof(a1));

printf("%d\n",sizeof(a2));

printf("%d\n",sizeof(a3));

printf("%d\n",sizeof(a4));

//struct A a1={'a',5.2356,3,"xuwe"};

printf("%d\n",&a1.c);

printf("%d\n",&a1.d);

printf("%d\n",&a1.s);

printf("%d\n",&a1.sf[5]);

printf("\n");

printf("%d\n",&a2.s);

printf("%d\n",&a2.sf[5]);

printf("%d\n",&a2.c);

printf("%d\n",&a2.d);

printf("\n");

printf("%d\n",&a3.c);

printf("%d\n",&a3.s);

printf("%d\n",&a3.sf[5]);

printf("%d\n",&a3.d);

printf("\n");

printf("%d\n",&a4.d);

printf("%d\n",&a4.sf[5]);

printf("%d\n",&a4.s);

printf("%d\n",&a4.c);

printf("\n");

return 0;

}

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 A)各成员所需内存量的总和 B)结构中第一个成员所需内存量 C)成员中占内存量最大者所需的容量 D)结构中最后一个成员所需内存量 2、以下对结构体类型变量td的定义中,错误的是C A)typedef struct aa {int n; fliat m; }AA; AA td; B)struct aa {int n; fliat m; }; struct aa td; C)struct yy {int n; float m; }aa; Struct yy td; D)struct yy { int n; float m; }td; 3、下列程序的输出结果是B 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); } A)5 B)6 C)7 D)8 4、设有如下说明A typedef struct yy { int n; char c; double x;}STD; 则以下选项中,能正确定义结构体数组并赋初值的语句是 A)STD tt[2]={{1,'A',62},{2, 'B',75}}; B)STD tt[2]={1,"A",62},{2, "B",75}; C)struct yy tt[2]={{1,'A'},{2, 'B'}}; D)struct yy tt[2]={{1,"A",62.5},{2,"B",75.0}}; 5、在32位IBM-PC机上使用C语言,若有如下定义 struct data { int i; char ch[8]; double f; }b; 则结构变量b占用内存的字节数是C A)13 B)8 C)16 D)24

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语言结构体习题及答案

第9章结构体 1.定义以下结构体类型 struct s { int a; char b; float f; }; 则语句printf("%d",sizeof(struct s))的输出结果为【】。 A) 3 B) 7 C) 6 D) 4 2.当定义一个结构体变量时,系统为它分配的内存空间是【】 A)结构中一个成员所需的内存容量 B)结构中第一个成员所需的内存容量 C)结构体中占内存容量最大者所需的容量 D)结构中各成员所需内存容量之和 3.定义以下结构体类型 struct s { int x; float f; }a[3]; 语句printf("%d",sizeof(a))的输出结果为【】 A) 4 B) 12 C) 18 D) 6 7.定义以下结构体类型 struct student { char name[10]; int score[50]; float average; }stud1; 则stud1占用内存的字节数是【】。 A) 64 B) 114 C) 228 D) 7 9、设有一结构体类型变量定义如下: struct date { int year; int month; int day; }; struct worklist { char name[20]; char sex; struct date birthday; } person; 若对结构体变量person的出生年份进行赋值时,下面正确的赋值语句是。。。。

A. year=1976 B. birthday.year=1976 C. person.birthday.year=1976 D. person.year=1976 1、若程序中有以下的说明和定义: struct abc { int x;char y; } 花括号后少了分号。 struct abc s1,s2; 则会发生的情况是______。 A) 编译时错B) 程序将顺序编译、连接、执行C) 能顺序通过编译、连接、但不能执行D) 能顺序通过编译、但连接出错

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位系统)

《动态分配内存与数据结构》课后习题

《动态分配内存与数据结构》习题 学号姓名 一、选择题 1、是一种限制存取位置的线性表,元素的存取必须服从先进先出的规则。 A.顺序表B.链表C.栈D.队列 2、是一种限制存取位置的线性表,元素的存取必须服从先进后出的规则。 A.顺序表B.链表C.栈D.队列 3、与顺序表相比,链表不具有的特点是。 A.能够分散存储数据,无需连续内存空间 B.插入和删除无需移动数据 C.能够根据下标随机访问 D.只要内存足够,没有最大长度的限制 4、如果通过new运算符动态分配失败,返回结果是。 A.-1 B.0 C.1D.不确定 5、实现深复制中,不是必须自定义的。 A.构造函数B.复制构造函数 C.析构函数D.复制赋值操作符函数 6、分析下列代码是否存在问题,选择合适的选项:。 int main(void) { int *p = new int [10]; p = new int [10]; delete [] p; p = NULL; return 0; } A.没有问题 B.有内存泄漏 C.存在空悬指针 D.存在重复释放同一空间 7、通过new运算符动态分配的对象,存储于内存中的。 A.全局变量与静态变量区 B.代码区 C.栈区 D.堆区 8、下列函数中,可以是虚函数。 A.构造函数 B.析构函数 C.静态成员函数 D.友元函数 9、关于通过new运算符动态创建的对象数组,下列判断中是错误的。 A. 动态创建的对象数组只能调用默认构造函数 B. 动态创建的对象数组必须调用delete []动态撤销 C. 动态创建的对象数组的大小必须是常数或常变量 D. 动态创建的对象数组没有数组名 10、顺序表不具有的特点是 A. 元素的存储地址连续 B. 存储空间根据需要动态开辟,不会溢出 C. 可以直接随机访问元素 D. 插入和删除元素的时间开销与位置有关 11、假设一个对象Ob1的数据成员是指向动态对象的指针,如果采用浅复制的方式复制该对象得到对象Ob2,那么在析构对象Ob1和对象Ob2时会的问题。 A. 有重复释放 B. 没有 C. 内存泄漏 D. 动态分配失败 12、假设对5个元素A、B、C、D、E进行压栈或出栈的操作,压栈的先后顺序是ABCDE,则出栈的先后顺序不可能是。 A. ABCDE B. EDCBA C. EDBCA D. BCADE 13、假设对4个元素A、B、C、D、E进行压栈或出栈的操作,压栈的先后顺序是ABCD,则出栈的先后顺序不可能是。 A. ABCD B. DCBA C. BCAD D. DCAB 14、通过new运算符动态创建的对象的存放在中。 A. 代码区 B. 栈区 C. 自由存储区 D. 全局数据区 15、链表不具有的特点是。 A. 元素的存储地址可以不连续 B. 存储空间根据需要动态开辟,不会溢出 C. 可以直接随机访问元素 D. 插入和删除元素的时间开销与位置无关 16、有关内存分配和释放的说法,下面当中错误的是 A.new运算符的结果只能赋值给指针变量 B.动态创建的对象数组必须调用delete []动态撤销 C.用new分配的空间位置是在内存的栈区 D.动态创建的对象数组没有数组名 17、关于栈,下列哪项不是基本操作 A.删除栈顶元素 B.删除栈底元素 C.判断栈是否为空 D.把栈置空 18、关于链表,说法错误的是

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

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

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

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

https://www.360docs.net/doc/7f2295802.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,

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

经验技巧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语言结构体的字节对齐及指定对齐方式

内存中结构体的内存对齐 一、字节对齐作用和原因: 对齐的作用和原因:各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取。比如有些架构的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;

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语言结构体(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语言程序设计 结构体与共用体

页眉内容 一、选择题 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;

相关文档
最新文档