第十九节 条件编译使用分析
1、#include的本质是将已经存在的文件内容嵌入到当前文件中;
2、#include的间接包含同样会产生嵌入文件内容的操作;
3、条件编译使得我们可以按不同的条件编译不同的代码段,因而可以产生不同的目标代码;
4、#if…#else…#endif被预处理器处理,而if…else…语句被编译器处理,必然编译进目标代码;
5、通过编译器命令能够定义预处理器使用的宏:
① gcc -Dname=Value file.c
② gcc -Dname file.c
6、条件编译可以避免重复包含同一个头文件;
7、条件编译是工程开发中可以区别不同产品线的代码;
8、条件编译可以定义产品发布和调试版;
第二十节 #error和#line分析
1、#error用于自定义一条编译错误信息;
2、#warning用于自定义一条编译警告信息;
3、#error和#warning常用于条件编译的情形;
4、#line常用于强制指定新的行号和文件名:#line linenum filename(可省略);
第二十一节 #pragma分析
1、#pragma message:
① message参数在大多的编译器中都有相似的实现;
②message参数在编译时输出消息到编译输出窗口中;
③message参数用于条件编译中科提示代码的版本信息;
2、#pragma once:
① #pragma once用于保证头文件只被编译一次;
② #pragma once是编译器相关的,不一定被支持;
3、#pragma pack(num):用于制定内存对齐方式,编译器默认的是4个字节对齐,内存对齐是不同的数据类型以一定的顺序在内存中存放;
4、为什么需要内存对齐?
① CPU对内存的读取是不连续的,分块读取,快的大小只能是1,2,4,…字节;
② 当读取操作的数据未对齐,则需要两次总线周期来访问内存,因此性能大打折扣;
注:struct占用内存的大小?
分析:
① 第一个成员起始于0偏移处;
② 每一个成员按其类型大小和pack参数中较小的一个进行对齐:
i. 偏移地址必须能被对齐参数整除;
ii. 结构体成员的大小取其内部长度最大的数据成员作为其大小;
③ 结构体总长度必须是所取对齐参数的整数倍;
eg: //对齐参数 偏移地址 大小
第二十二节 #和##操作符
1、#运算符用于在预处理期将宏参数转换为字符串;
2、##运算符用于在预处理期粘连两个标识符;
3、编译器不知道#和##存在,他们只在宏定义中生效;
第二十三节 指针的本质分析
1、在指针声明时,号表示所声明的变量是指针;
2、在指针使用时,号表示取指针所指向的内存空间中的值;
3、指针是变量,因此可以声明指针参数;
4、当一个函数体内部需要改变实参的值,则需要使用指针参数;
5、指针保存的是内存地址,在32位操作系统中占用4个字节;
6、口诀:左数右指
① 当const出现在号的左边时,指针指向的数据为常量;
② 当const出现在号的右边时,指针本身为常量;
第二十四节 数组的本质分析
1、数组名代表数组首元素的地址,数组的地址需要用取地址符号得到;
2、数组的首元素的地址值与数组的地址值相同;
3、数组首元素的地址与数组地址意义不同,值相同但所占有的存储空间不同;
4、数组名不包括数组的长度信息,在表达式中数组名只能作为右值使用;
5、数组名其实并不是指针,不能将其等同于指针;