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的更多相关文章

  1. CSAPP阅读笔记-数组分配与访问-来自第三章3.8的笔记-P176-P183

    这一节比较简单,仅记录几个比较重要的点: 1.C语言允许对指针进行运算,计算出的值会根据该指针引用的数据类型大小进行伸缩. 例子: 其中,xE是数组的起始地址.注意,指针运算时,若最终结果为指针,则指 ...

  2. CSAPP阅读笔记-gcc常用参数初探-来自第三章3.2的笔记-P113

    gcc是一种C编译器,这次我们根据书上的代码尝试着使用它. 使用之前,先补充前置知识.编译器将源代码转换为可执行代码的流程:首先,预处理器对源代码进行处理,将#define指定的宏进行替换,将#inc ...

  3. CSAPP阅读笔记-栈帧-来自第三章3.7的笔记-P164-P176

    1.基本结构: 如上图所示,是通用的栈帧结构.大致分两块,调用者函数P和被调用者函数Q. 对P来说,要做的工作是把传递参数中多于6个的部分压栈,随后把Q返回时要执行的下一条指令的地址压栈. 对Q来说, ...

  4. CSAPP阅读笔记-汇编语言初探(控制类指令)-来自第三章3.6的笔记-P135-P163

    1.正溢出与负溢出: 首先,一个正数与一个负数相加,不可能溢出,因为结果的绝对值一定小于两个加数的绝对值,既然两个加数能合理表示出来,结果一定也能合理表示出来. 其次,正溢出是由于两个很大的正数相加, ...

  5. CSAPP阅读笔记-变长栈帧,缓冲区溢出攻击-来自第三章3.10的笔记-P192-P204

    一.几个关于指针的小知识点: 1.  malloc是在堆上动态分配内存,返回的是void *,使用时会配合显式/隐式类型转换,用完后需要用free手动释放. alloca是标准库函数,可以在栈上分配任 ...

  6. CSAPP阅读笔记-汇编语言初探(算术和逻辑操作类指令)-来自第三章3.5的笔记-P128-P135

    1.算术和逻辑操作类指令分四类:加载有效地址,一元操作,二元操作和移位,如下: 2. leaq指令,类似mov指令,它左侧的数看似是给出一个地址,在内存中从给定的地址取操作数,传给右边的目的地.但其实 ...

  7. Java程序设计(2021春)——第三章类的重用笔记与思考

    Java程序设计(2021春)--第三章类的重用笔记与思考 本章概览: 3.1 类的继承(概念与语法) 3.2 Object类(在Java继承最顶层的类) 3.3 终结类和终结方法(只能拿来用,不可以 ...

  8. CSAPP阅读笔记-汇编语言初探(数据传送类指令)-来自第三章3.2-3.3的笔记-P115-P128

    1.如何由机器代码生成汇编代码? objdump -d再加上文件名即可直接在终端看到由反汇编器恢复的汇编代码.注意,文件名并不一定得是.o文件,任何可执行文件都可以. 结果如下: 仅列举了反汇编tes ...

  9. CSAPP阅读笔记-32位64位的区别--来自第三章引言的笔记--P110

    仅从寻址上看,32位和64位机器能寻址的内存空间大小不同. 需要知道的是,计算机系统对存储器作了抽象,程序“认为”内存是一个很大的字节数组,然而实际上它是由多个硬件存储器和操作系统组合起来实现的. 程 ...

随机推荐

  1. python切片、列表解析、元组

    1.列表解析 test = [x**2 for x in range(1,11)] 2.切片 test1 = ["a","b","c",&q ...

  2. kafka安装配置及操作(官方文档)http://kafka.apache.org/documentation/(有单节点多代理配置)

    https://www.cnblogs.com/biehongli/p/7767710.html w3school https://www.w3cschool.cn/apache_kafka/apac ...

  3. imagelist用法

    1.添加一个Imagelist控件,并双击控件图标如下图 2.点击新增按钮

  4. Android-Intent意图传递数据

    Intent意图传递基本数据类型: OuterActivity 激活启动 OneActivity 用Intent携带基本数据类型: /** * Intent意图传递数据到另外一个Activity */ ...

  5. 强大的CSS 属性选择符 配合 stylish 屏蔽新浪微博信息流广告

    新建一条微博域名下的规则: @-moz-document domain("weibo.com") { #v6_pl_rightmod_rank,#v6_pl_rightmod_ad ...

  6. 生成文件的MD5、SHA、SHA256

    生成文件的MD5.SHA.SHA256 Linux系统生成MD5.SHA.SHA256md5sum file1.zip  >> MD5.txt sha1sum file1.zip > ...

  7. 菜鸟的Xamarin.Forms前行之路——windows下VS运行ios模拟器调试

    在Xamarin.Forms项目中,运行安卓模拟器是很方便的,但是想要运行IOS模拟器,相对而言是困难一点. 在参考一些资料后,发现很多是与Xamarin.studio有关的方法,尝试了许久没有成功. ...

  8. 2.css的引入方式

    网页中引用CSS样式 内联样式 行内样式表 外部样式表 ..链接式 ..导入式 内嵌方式 style标签 <!doctype html> <html> <head> ...

  9. 1.IPtable基础命令总结

    iptables概念 规则查询 #查看对应表中的所有规则 iptables -t 表名 -L #查看表的指定链中的规则 iptables -t 表名 -L 链名 #查看对应表中的所有规则, -v显示跟 ...

  10. 【bzoj5084】 hashit(广义SAM+set)

    题面 传送门 题解 后缀平衡树是个啥啊我不会啊-- 那么我们来考虑一下\(SAM\)的做法好了 不难发现它的本义是要我们维护一棵\(trie\)树,并求出\(trie\)树上每一个节点到根的这段串的不 ...