10.1.1 程序的编译和执行 以#开头的代码都属于预处理器处理的步骤 #include 将头文件的内容包含进入当前源文件中 #define 展开宏定义 #ifdef 处理条件编译指令(#ifdef、ifndef、#if、#else、#elif、#endif) #other 处理其他宏指令(#error、#warning、#line、#pragma) 预处理器 其他功能如下: 处理预先定义的宏:例如__DATE__ FILE(其后均为两条下划线) 处理注释:用一个空格代替连续的注释 处理三元符 注意 编译器对预先处理过的代码进行词法分析、语法分析和语义分析,将符合规则的程序转化为等价的汇编代码 汇编器将编译器生成的汇编代码翻译成为计算机可以识别的机器指令,并生成目标文件。之所以不将源程序之间转化成为机器指令,而分成了多级转化,是为了在不同的阶段应用不同的优化技术,并且这些优化技术已经很强。可以保证各个阶段分别优化之后可以生成更为高效的机器指令 链接器 将所有的目标程序链接在一起,无论是静态还是动态链接,最终都可以生成一个可以在机器上运行的可执行的程序。运行可执行程序就会得到执行的结果 10.1.2 金典面试题解析 简述#include<>和#include“ ”之间的区别 主要目的都是为了 将指定文件中的内容引入到当前的文件,但是搜索被引入文件的时候,二者采用了不同的搜索策略 #include<>:直接从编译器指定的路径处开始搜索 #include“ ”:从程序所在的目录进行搜索,如果搜索失败,再从编译器指定的路径处开始搜索 用户自定义的文件只能使用#include“ ”,如果系统文件使用#include“ ”,会在用户目录进行无意义的搜索尝试,如果找不到,再按照编译器指定的路径处进行搜索 简述#和##在define里面的作用
#运算符会将其前后参数转化成为字符串 ##运算符会将前后的参数进行字符串的连接
assert 断言的概念 assert是一个带参数的宏定义,不是一个函数,头文件在assert.h文件里面 使用assert检测条件表达式,如果表达式为假,表示检测失败,程序会向标准错误流stderr输出一条错误的信息,再次调用函数abort函数终止程序的执行 频繁使用assert会降低程序的性能,增加额外的开销,一般是调试中使用宏,调试完成之后,在#include语句之前 使用#define DEBUG禁用assert宏定义 assert虽然可以检测多个条件,但是最好不要如此使用,因为一旦出错,不知道是哪个条件导致的错误,因此没有任何的意义 不要在assert里面修改变量的数值,因为assert只会在debug版本中使用,一旦使用了RELEASE版本,所有的assert都会失效。 断言的目的是为了捕获可控但是不应该发生的情况,不适合外部接口的函数检测,因为外部输入的参数是一个不可控的事件,应该使用if进行判定 断言用于 内部函数,其参数检测使用断言;因为函数的使用者是程序开发者,错误的参数是可控并且不该发生的情况 assert用于程序的DEBUG版本检测条件的表达式,如果结果为假,则输出诊断信息并且终止程序的执行