(c/c++学习笔记三) 结构体与联合体的字节对齐
来源:互联网 发布:网络通信安全管理员 编辑:程序博客网 时间:2024/05/20 10:21
结构体字节对齐
在用sizeof运算符求算某结构体所占空间时,并不是简单地将结构体中所有元素各自占的空间相加,这里涉及到内存字节对齐的问题。从理论上讲,对于任何 变量的访问都可以从任何地址开始访问,但是事实上不是如此,实际上访问特定类型的变量只能在特定的地址访问,这就需要各个变量在空间上按一定的规则排列, 而不是简单地顺序排列,这就是内存对齐。
内存对齐的原因:
1)某些平台只能在特定的地址处访问特定类型的数据;
2)提高存取数据的速度。比如有的平台每次都是从偶地址处读取数据,对于一个int型的变量,若从偶地址单元处存放,则只需一个读取周期即可读取该变量;但是若从奇地址单元处存放,则需要2个读取周期读取该变量。
win32平台下的微软C编译器对齐策略:
1)结构体变量的首地址能够被其最宽数据类型成员的大小整除。编译器在为结构体变量开辟空间时,首先找到结构体中最宽的数据类型,然后寻找内存地址能被该数据类型大小整除的位置,这个位置作为结构体变量的首地址。而将最宽数据类型的大小作为对齐标准。
2)结构体每个成员相对结构体首地址的偏移量(offset)都是每个成员本身大小的整数倍,如有需要会在成员之间填充字节。编译器在为结构体成员开辟空 间时,首先检查预开辟空间的地址相对于结构体首地址的偏移量是否为该成员大小的整数倍,若是,则存放该成员;若不是,则填充若干字节,以达到整数倍的要 求。
3)结构体变量所占空间的大小必定是最宽数据类型大小的整数倍。如有需要会在最后一个成员末尾填充若干字节使得所占空间大小是最宽数据类型大小的整数倍。
下面看一下sizeof在计算结构体大小的时候具体是怎样计算的
1.test1 空结构体
typedef struct node{ }S;
则sizeof(S)=1;或sizeof(S)=0;
在C++中占1字节,而在C中占0字节。
2.test2
typedef struct node1{ int a;//偏移量是0,占用4字节 char b;//偏移量是4,数据类型是char(1字节,4是1的倍数,占用1字节 short c;//偏移量是5,数据类型是short(2字节),5不是2的倍数,补位到6,占用2字节}S1;//长度为8,是最宽数据类型int(4字节)的整数倍
则sizeof(S1)=8。这是因为结构体node1中最长的数据类型是int,占4个字节,因此以4字节对齐,则该结构体在内存中存放方式为
|--------int--------| 4字节
|char|----|--short-| 4字节
总共占8字节
3.test3
typedef struct node2{ char a;//偏移量是0,占用1字节 int b;//偏移量是1,数据类型是int(4字节)1不是4的倍数,补位至4,占用4字节 short c;//偏移量是8,数据类型是short(2字节)8是2的倍数,占用2字节}S2;//长度是10,不是最宽数据类型int(4字节的倍数),所以补位长度至12
则siezof(S3)=12.最长数据类型为int,占4个字节。因此以4字节对齐,其在内存空间存放方式如下:
|char|----|----|----| 4字节
|--------int--------| 4字节
|--short--|----|----| 4字节
总共占12个字节
4.test4 含有静态数据成员
typedef struct node3{ int a; short b; static int c;}S3;
则sizeof(S3)=8.这里结构体中包含静态数据成员,而静态数据成员的存放位置与结构体实例的存储地址无关(注意只有在C++中结构体中才能含有静态数据成员,而C中结构体中是不允许含有静态数据成员的)。其在内存中存储方式如下:
|--------int--------| 4字节
|--short-|----|----| 4字节
而变量c是单独存放在静态数据区的,因此用siezof计算其大小时没有将c所占的空间计算进来。
5.test5 结构体中含有结构体
typedef struct node4{ bool a;//偏移量是0,占用1字节 S1 s1;//偏移量是1,S1中最宽数据类型是int(4字节,1不是4的倍数,补位4,占用8字节 short b;//偏移量是12,数据类型是short(2字节),12是2的倍数,占用2字节}S4;//长度是14,不是最大数据类型int(4字节)的倍数,补位至16
则sizeof(S4)=16。是因为s1占8字节,而s1中最长数据类型为int,占4个字节,bool类型1个字节,short占2字节,因此以4字节对齐,则存储方式为
|-------bool--------| 4字节
|-------s1----------| 8字节
|-------short-------| 4字节
6.test6
typedefstruct node5{ bool a;//偏移量是0,占用1字节 S1 s1;//偏移量是1,S1中最宽数据类型是int(4字节)1不是4的倍数,补位至4,占用8字节 double b;//偏移量是12,数据类型是double(8字节),12不是8的倍数,补位至16,占用8字节 int c;//偏移量是24,数据类型是int(4字节),24是4的倍数,占用4字节}S5;//长度为28,最宽数据类型是double(8字节)28不是8的倍数,补位至32字节
则sizeof(S5)=32。是因为s1占8字节,而s1中最长数据类型为int,占4字节,而double占8字节,因此以8字节对齐,则存放方式为:
|--------bool--------| 8字节
|---------s1---------| 8字节
|--------double------| 8字节
|----int----|---------| 8字节
7.test7
若在程序中使用了#pragma pack(n)命令强制以n字节对齐时,默认情况下n为8.
则比较n和结构体中最长数据类型所占的字节大小,取两者中小的一个作为对齐标准。
若需取消强制对齐方式,则可用命令#pragma pack()
如果在程序开头使用命令#pragma pack(4),对于下面的结构体
typedef struct node5{ bool a; S1 s1; double b; int c;}S5;
则sizeof(S5)=24.因为强制以4字节对齐,而S5中最长数据类型为double,占8字节,因此以4字节对齐。在内存中存放方式为:
|-----------a--------| 4字节
|--------s1----------| 4字节
|--------s1----------| 4字节
|--------b-----------| 4字节
|--------b-----------| 4字节
|---------c----------| 4字节
总结一下,在计算sizeof时主要注意一下几点:
1)若为空结构体,则只占1个字节的单元
2)若结构体中所有数据类型都相同,则其所占空间为 成员数据类型长度×成员个数
若结构体中数据类型不同,则取最长数据类型成员所占的空间为对齐标准,数据成员包含另一个结构体变量t的话,则取t中最 长数据类型与其他数据成员比较,取最长的作为对齐标准,但是t存放时看做一个单位存放,只需看其他成员即可。
3)若使用了#pragma pack(n)命令强制对齐标准,则取n和结构体中最长数据类型占的字节数两者之中的小者作为对齐标准。
- (c/c++学习笔记三) 结构体与联合体的字节对齐
- <C语言>结构体与联合体(共用体)的地址排布问题(内存字节对齐)
- C语言结构体的字节对齐
- C语言结构体的字节对齐
- C语言结构体的字节对齐
- C语言结构体的字节对齐
- c结构体字节对齐
- 结构体和联合体的字节对齐问题
- 结构体联合体的字节对齐问题详解:
- C语言学习笔记10-结构体、枚举、联合体
- C/C++学习笔记4 结构体联合体枚举
- 联合体和结构体字节对齐
- C语言学习笔记--------伊能C语言学习笔记------C语言结构体字节对齐机制
- 学习笔记-C/C++-结构体与sizeof,内存对齐的题目怎么做
- 学习笔记-C/C++-结构体与sizeof,内存对齐的题目怎么做
- 结构体,联合体的对齐
- [C++]字节对齐与结构体大小
- [C++]字节对齐与结构体大小
- Cocos2d-X Lua脚本语言简介(一)
- eclipse 从svn导入项目 报错A project with that name already exists in the workspace
- Linux的启动顺序
- [C++]全局变量
- mvc3 + easyui 开发学习笔记------- easyui combobox 加载列表项
- (c/c++学习笔记三) 结构体与联合体的字节对齐
- 撒地方该规划和规范化和规范的法规和计划
- 一种基于Word文档的手写批注实现方法
- AFNetworking
- oc 内存管理
- Debug application
- C小鸟
- IOS开发之__bridge,__bridge_transfer和__bridge_retained
- IOS学习笔记之五:Memory Management 内存管理