作者:喜欢猫咪的的程序员
专栏:《C语言》
喜欢的话:世间因为少年的挺身而出,而更加瑰丽。 ——《人民日报》
目录
在ANSI C的任何一种实现中,存在两个不同的环境。
- 第1种是翻译环境,在这个环境中源代码被转换为可执行的机器指令。
- 第2种是执行环境,它用于实际执行代码
编译一个C语言程序是一个多阶段的过程。从总体上看,这个过程可以分成四个独立的阶段。预处理、编译、汇编和连接
我们先来看看这4个过程的流程图:
1.一个文件经过编译器生成对应的目标文件
2.多个目标文件与链接库一起生成链接器,最终生成可执行程序。(编译过程)
我们先来了解一下编译过程中各个阶段的操作指令:
1. 预处理 选项 gcc -E test.c -o test.i
预处理完成之后就停下来,预处理之后产生的结果都放在test.i文件中。
2. 编译 选项 gcc -S test.c
编译完成之后就停下来,结果保存在test.s中。
3. 汇编 gcc -c test.c
汇编完成之后就停下来,结果保存在test.o中。
我们可以通过上述的各个指令来观察各个阶段。
下图是各个阶段会做的事情以及操作指令:
这些预定义符号都是语言内置的。
以上预定义符号如何使用呢?
参考下图:
语法:
#define name stuff
stuff 只要合法都可以,数字 字符串甚至是一串代码
运用如下:
#define name( parament-list ) stuff
其中的 parament-list 是一个由逗号隔开的符号表,它们可能出现在stuff中注意:
参数列表的左括号必须与name紧邻。
如果两者之间有任何空白存在,参数列表就会被解释为stuff的一部分。
如何运用如下:
注意:能加括号尽量加括号,避免出现歧义,造成错误。
避免出现下面这种情况:
我们都知道 #define会替换,那他替换有什么原则吗?如下:
- 使用 # ,把一个宏参数变成对应的字符串。
- ##可以把位于它两边的符号合成一个符号。它允许宏定义从分离的文本片段创建标识符。
注:这样的连接必须产生一个合法的标识符。否则其结果就是未定义的。
宏的优点:
- 宏通常被应用于执行简单的运算。
- 宏比函数在程序的规模和速度方面更胜一筹。
- 更为重要的是函数的参数必须声明为特定的类型。
所以函数只能在类型合适的表达式上使用。反之这个宏怎可以适用于整形、长整型、浮点型等可以用于>来比较的类型。宏是类型无关的。宏的缺点:
- 每次使用宏的时候,一份宏定义的代码将插入到程序中。除非宏比较短,否则可能大幅度增加程序的长度。
- 宏是没法调试的。
- 宏由于类型无关,也就不够严谨。
- 宏可能会带来运算符优先级的问题,导致程容易出现错
- 把宏名全部大写
- 函数名不要全部大写
这条指令用于移除一个宏定义。
查找策略:先在源文件所在目录下查找,如果该头文件未找到,编译器就像查找库函数头文件一样在标
准位置查找头文件。
如果找不到就提示编译错误。
查找头文件直接去标准路径下去查找,如果找不到就提示编译错误