CSAPP阅读笔记-struct, union, 数据对齐-来自第三章3.9的笔记-P183-P191
1.数据对齐
为什么要对齐:通俗点解释就是CPU对数据访问时,每次都是取固定数量的字节数,假如一次取4个字节,若有个int存在0x01-0x04,则一次就能取出,若存在0x03-0x06,则需要分两次才能取到(第一次0x01-0x04,第二次0x05-0x08),这样会降低CPU效率,更何况还有像short,char之类的不是4个字节的数据。因此,编译器会对数据进行强制对齐。
对齐规则:
1.任何K字节的基本对象的地址必须是K的倍数
2.在结构末尾根据需要会做一些填充,使其一旦被拓展为数组时可以满足条件1
例子:
struct S1
{
int i;
char c;
int j;
};
分析:
i起始地址偏移量为0,满足条件1,占用4个字节,c起始地址偏移量为4,满足条件1,占用1个字节,本来j起始地址偏移量应该为5,然而为了满足条件1,编译器会在c后面填充3个字节,使j起始地址偏移量为8,另外j占用4个字节,所以S1一共占用12个字节。再看一下是否满足条件2:一旦声明了 struct S1[2],第二个结构体的第一个元素i的起始地址偏移量为12,满足条件1,因此S1一共占用12个字节没问题。
再来一个例子:
struct S2
{
int i;
int j;
char c;
};
分析:
i起始地址偏移量为0,满足条件1,占用4个字节,j起始地址偏移量为4,满足条件1,占用4个字节,c起始地址偏移量为8,满足条件1,占用1个字节,所以S2一共占用9个字节。再看一下是否满足条件2:一旦声明了 struct S2[2],第二个结构体的第一个元素i的起始地址偏移量为9,不满足条件2,因此结构体需在c后面填充3个字节,这样第二个结构体的第一个元素i的起始地址偏移量变为12,满足条件2,综上S2一共占用12个字节。
看起来似乎没问题,但其实上面的分析有个误区,下面通过一道例题来展现:

A,B,C,D都没问题,但E中,按之前的分析,a的起始地址应该是0,每个P3结构体占10个字节,P2结构体的第一个元素是int,所以t的起始地址应该是4的倍数,因此起始地址为20没问题,因为P2占16个字节,所以P5总大小为36个字节。
然而,答案是t的起始地址为24,P5总大小为40个字节。
仔细查看书前面的描述,书里并没有清晰地描述过第二条结论,我觉得第二条自己的总结有误,现在修正为:
2.在结构末尾根据需要会做一些填充,使其一旦被拓展为数组时可以满足条件1,而且拓展时是以数组中下一个结构体元素中数据大小最大那个元素为标准来对齐的。
现在重新来看E,a的起始地址为0,每个P3占10个字节,所以a[0]先占10个字节,又因为P3中最大的元素是short,因此a[1]起始地址为10,符合条件2,此时t的起始地址本应是20,但P2中最大的元素为long,因此要按8字节对齐,所以t的起始地址为24,P2占16个字节,因此P5一共占40个字节。
我们使用新修改的结论来看S2那个例子,发现也没有问题,之所以之前没看出问题,那个例子中最大的元素大小刚好和第一个元素i大小相同,所以问题没有暴露。
另外,根据之前的几个例题,很明显可以看出,结构体中元素排布的顺序不同,会直接影响浪费的空间大小,若要最小化浪费的空间,按从大到小的顺序来排即可,自己思考下就明白了,相应例题可以看习题3.45。
2.union和struct
它们的区别其实很简单,struct类似数组,把不同类型的元素按顺序存储在内存中一段连续区域中,而union则是所有元素起始地址都相同(当然,若某个元素是数组,数组中所有元素仍是顺序排列的),因此union的大小等于其最大元素的大小。
什么时候使用union呢?
当我们知道某结构中的元素是互斥使用时,就可以把它声明成union来节约空间。
例子:

node_t一共占用了24个字节的空间。
分析:
首先,枚举类型本质上是一组常数的集合体,只是这些常数有各自的命名。由于枚举变量的赋值,一次只能存放枚举结构中的某个常数。所以枚举变量的大小,实质是常数所占内存空间的大小(常数为int类型,当前主流的编译器中一般是32位机器和64位机器中int型都是4个字节),枚举类型所占内存大小也是这样。
以上这段话引用自https://blog.csdn.net/bulebin/article/details/54388735
好了,枚举变量type占4个字节,union变量info里最大数据类型为8个字节,因此需要8字节对齐,编译器在type后面填充4个字节,然后union中internal结构体和data数组起始地址相同,且都占16个字节,因此node_t一共占用8+16=24个字节。
最后要注意的一点是union中的字节序:
例子:

本书前几章提到过小端法机器的特点是高字节存高地址,低字节存低地址,以小端法机器为例来看本例:
显然u数组一共占8个字节,且起始地址和d相同,按照小端法来看,那么d的低4个字节存的是u[0],高4个字节存的是u[1].
CSAPP阅读笔记-struct, union, 数据对齐-来自第三章3.9的笔记-P183-P191的更多相关文章
- CSAPP阅读笔记-数组分配与访问-来自第三章3.8的笔记-P176-P183
这一节比较简单,仅记录几个比较重要的点: 1.C语言允许对指针进行运算,计算出的值会根据该指针引用的数据类型大小进行伸缩. 例子: 其中,xE是数组的起始地址.注意,指针运算时,若最终结果为指针,则指 ...
- CSAPP阅读笔记-gcc常用参数初探-来自第三章3.2的笔记-P113
gcc是一种C编译器,这次我们根据书上的代码尝试着使用它. 使用之前,先补充前置知识.编译器将源代码转换为可执行代码的流程:首先,预处理器对源代码进行处理,将#define指定的宏进行替换,将#inc ...
- CSAPP阅读笔记-栈帧-来自第三章3.7的笔记-P164-P176
1.基本结构: 如上图所示,是通用的栈帧结构.大致分两块,调用者函数P和被调用者函数Q. 对P来说,要做的工作是把传递参数中多于6个的部分压栈,随后把Q返回时要执行的下一条指令的地址压栈. 对Q来说, ...
- CSAPP阅读笔记-汇编语言初探(控制类指令)-来自第三章3.6的笔记-P135-P163
1.正溢出与负溢出: 首先,一个正数与一个负数相加,不可能溢出,因为结果的绝对值一定小于两个加数的绝对值,既然两个加数能合理表示出来,结果一定也能合理表示出来. 其次,正溢出是由于两个很大的正数相加, ...
- CSAPP阅读笔记-变长栈帧,缓冲区溢出攻击-来自第三章3.10的笔记-P192-P204
一.几个关于指针的小知识点: 1. malloc是在堆上动态分配内存,返回的是void *,使用时会配合显式/隐式类型转换,用完后需要用free手动释放. alloca是标准库函数,可以在栈上分配任 ...
- CSAPP阅读笔记-汇编语言初探(算术和逻辑操作类指令)-来自第三章3.5的笔记-P128-P135
1.算术和逻辑操作类指令分四类:加载有效地址,一元操作,二元操作和移位,如下: 2. leaq指令,类似mov指令,它左侧的数看似是给出一个地址,在内存中从给定的地址取操作数,传给右边的目的地.但其实 ...
- Java程序设计(2021春)——第三章类的重用笔记与思考
Java程序设计(2021春)--第三章类的重用笔记与思考 本章概览: 3.1 类的继承(概念与语法) 3.2 Object类(在Java继承最顶层的类) 3.3 终结类和终结方法(只能拿来用,不可以 ...
- CSAPP阅读笔记-汇编语言初探(数据传送类指令)-来自第三章3.2-3.3的笔记-P115-P128
1.如何由机器代码生成汇编代码? objdump -d再加上文件名即可直接在终端看到由反汇编器恢复的汇编代码.注意,文件名并不一定得是.o文件,任何可执行文件都可以. 结果如下: 仅列举了反汇编tes ...
- CSAPP阅读笔记-32位64位的区别--来自第三章引言的笔记--P110
仅从寻址上看,32位和64位机器能寻址的内存空间大小不同. 需要知道的是,计算机系统对存储器作了抽象,程序“认为”内存是一个很大的字节数组,然而实际上它是由多个硬件存储器和操作系统组合起来实现的. 程 ...
随机推荐
- 优秀前端工程师必备: (总结) 清除原生ios按钮样式
写移动端的web开发时, 需要清除IOS本身的各种样式: 1.消除ios按钮原生样式, 给按钮加自定义样式: input[type="button"], input[type=&q ...
- 关于iReport中纸张的大小 换算
在iReprot里中进行报表设计时 第一步先确定纸张的大小 如A4纸 直接选就行了 A2 A3一样的,但还会在这种情况这种纸没有选择的怎么办? 比如 那种代小孔的纸 279*241m ...
- 第几天——第九届蓝桥杯C语言B组(省赛)第一题
原创 标题:第几天 2000年的1月1日,是那一年的第1天. 那么,2000年的5月4日,是那一年的第几天? 注意:需要提交的是一个整数,不要填写任何多余内容. 这题是送分题,只需要注意一下2000年 ...
- Dubbo RPC源码解读
https://yq.aliyun.com/articles/272405#27 本文代码摘录的时候,将一些与本流程无关的内容去掉了,如有需要请看源码. 一.闲言碎语 使用rpc框架已经多年了,虽然之 ...
- Git SSH Key
一.设置Git的user name和email: $ git config --global user.name "hhl_vip" $ git config --global ...
- Android-自定义RadioButton
1.控件RadioButton需要用RadioGroup包裹起来,才能使用2.RadioButton必须设置ID才能实现单选功能3.RadioGroup有方向(垂直方向 和 水平方向)默认是垂直方向 ...
- ibatis 参数之 String
<select id="query_cust_name" resultClass="_custForm" parameterClass="Str ...
- EDM模板制作规范
为了保证最大的兼容性,在制作HTML的email页面时,请严格按照规范来书写: 1.页面宽度推荐500px,最大不要超过750px: 2.制作HTML的email页面时,不使用css+div来布局,最 ...
- iis 部署webapi常见错误及解决方案
iis 部署webapi常见错误及解决方案 错误一: 原因:asp.net web api部署在Windows服务器上后,按照WebAPI定义的路由访问,老是出现404,但定义一个静态文件从站点访问, ...
- 【OCP|052】OCP换题库,052最新题库及答案整理-第10题
10.Which two are true about consistent database backups? A) They can only be taken when a RECOVERY C ...