1.翻译环境,在这个环境中源代码被转换为可执行的机器指令
2.执行环境,它用于实际执行代码
组成一个程序的每个源文件通过编译过程分别转换成目标代码(object code) 每个目标文件由链接器(linker)捆绑在一起,形成一个单一而完整的可执行程序
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 定义标识符
#define 定义宏
在程序中扩展#define定义符号和宏时,需要涉及几个步骤
1.在调用宏时,首先对参数进行检查,看看是否包含任何由#define定义的符号。如果是,它们首先 被替换
2.替换文本随后被插入到程序中原来文本的位置。对于宏,参数名被他们的值所替换
3.最后,再次对结果文件进行扫描,看看它是否包含任何由#define定义的符号。如果是,就重复上 述处理过程
4.宏参数和define 定义中可以出现其他define定义的符号。但是对于宏,不能出现递归
5.当预处理器搜索#define定义的符号的时候,字符串常量的内容并不被搜索
# ,把一个宏参数变成对应的字符串
##可以把位于它两边的符号合成一个符号 它允许宏定义从分离的文本片段创建标识符
define ADD_TO_SUM(num, value) \* sum##num += value; ... ADD_TO_SUM(5, 10);//作用是:给sum5增加*10
属 性 | #define定义宏 | 函数 |
---|---|---|
代 码 长 度 | 宏代码会被插入到程序中,程序的长度会大幅度增长 | 函数代码只出现于一个地方;每次使用这个函数时,都调用同一份代码 |
执 行 速 度 | 更快 | 存在函数的调用和返回的额外开 销(压栈和销毁),所以慢一些 |
操 作 符 优 先 级 | 邻近操作符的优先级可能会产生 不可预料的后果,写宏时要多加括号 | 函数参数只在函数调用的时候求 值一次,它的结果值传递给函 数 |
带 有 副 作 用 的 参 数 | 参数可能被替换到宏体中的多个位置,所以带有副作 用的参数求值可能会产生不可预料的结果 | 函数参数只在传参的时候求值一 次,结果更容易控制 |
参 数 类 型 | 宏的参数与类型无关,只要对参数的操作是合法的,它就可以使用于任何参数类型 | 函数的参数是与类型有关的,如 果参数的类型不同,就需要不同 的函数 |
调 试 | 宏不方便调试的 | 函数是可以逐语句调试的 |
递 归 | 宏是不能递归的 | 函数是可以递归 |