文章目录
预处理器
预处理指令从#开始,到后面的第一个换行符为止。所以只可以占据一行哦
预处理指令的有效范围是定义处到文件结尾。如果宏通过头文件引入,则宏的作用域是#include指令开始到文件结尾。所以本质上,宏具有文件作用域。
#前面可以有空格或制表符,可以出现在源文件的任何地方
预处理之前,编译器要做三件事
我很惊讶,预处理本来就是执行程序之前的操作了,没想到预处理器之前还有“预处理”。
这些处理基本都是翻译,替换,和代码本身也是无关的。
把源代码的字符映射到源字符集
写代码时可能用到各种编码,不一定只用到ASCII码,扩展字符集比如UTF-8都是多字节编码,可以使得C更加国际化,所以编译器需要把程序员使用的编码映射到C自己支持的扩展字符。
删除反斜杠后面是换行符的实例(把两个物理行转换为一个逻辑行)
非常easy,不过我很震惊这竟然是预处理之前编译器会做的事情,以前没仔细研究还真不知道这件事编译器是什么时候做的。看来编译器真的很重要,需要做好多事情啊,有的是为了方便程序员,有的又是需要遵从C标准,甚至有时候是要和操作系统来往。
physical line
logical line
举个栗子,内容太长,一行写不下,可以在反斜杠后面换行,编译器会知道你的意思,其实仍然只有一行,只是物理上占用了两行。
puts("Enter a line: \
(empty line to quit.)");
pycharm也允许这么做
把文本划分为 预处理器记号序列 空白序列 注释序列
原来注释在预处理之前就被抹去了
做完这三件事情,编译器就会让程序进入预处理阶段,预处理器就开始查找每一行中以#开头的预处理指令。
#define(不止可以定义符号常量!)
除了#include之外,用的最多的预处理指令只有一个,就是#define,用来定义符号常量(也叫明示常量 manifest constant),但是#define很强大,还有很多其他用途。
#define指令的结构分为三部分:
第一部分: #define
第二部分: 宏
第三部分: 替换体
替换体是记号型字符串,记号(token), 记号不能有空格
宏
对于什么是宏,我一直非常不懂,困惑了很久很久,今天终于明白了,很简单,也明白了为啥word那种文本处理软件也有宏的概念和代码了,但是不明白为啥他会被叫做macro,为什么叫这个名字呢?毕竟名字肯定和特性有点关系
宏就是#define后面紧跟着的缩写,一般都是大写的,根据宏后面的替换体是指还是函数,宏又分为类对象宏(object-like macro)和类函数宏(function-like macro)。
宏的命名遵循C变量命名规则,中间不可以有空格,只可以用字母,数字,下划线,首字符不可为数字。
宏展开 macro expansion就是从宏变为替换体的过程。
空宏
如
#define GOOD
只有宏,没有替换体就是空宏
类对象宏 object-like macro
示例
#include <stdio.h>
#define TWO 2 //数值常量
//字符串常量
#define OW "Consistency is the last refuge of \
the unimaginative. - Oscar Wilde "/*一致性是缺乏想象力的人最后的避难所*/
//符号常量的表达式,宏定义中包含已经定义的宏(嵌套宏定义)
#define FOUR TWO*TWO
//函数表达式
#define PX printf("x is %d.\n", x)
//格式字符串
#define FMT "x is %d.\n"
int main()
{
int x = TWO;
PX;
x = FOUR;//先替换为x=TWO*TWO;再替换为x=2*2
printf(FMT, x);
printf("%s\n", OW);
printf("TWO: OW\n");//双引号中的宏不会被替换
return 0;
}
x is 2.
x is 4.
Consistency is the last refuge of the unimaginative. - Oscar Wilde
TWO: OW
函数中如果要多次使用格式字符串,可以像上面那样用宏定义,把格式字符串作为替换体;当然也可以用一个const char指针指向这个字符串
const char *st = "x is %d.\n";
但是宏的作用不是可以完全由const替代的,但是C++中允许用const值作为常量表达式的一部分
类函数宏 function-like macro(在#define 中使用参数)
之前说getchar(), putchar()不是函数,而是宏,我不明白,原来就是类函数宏呀
示例 函数宏的陷阱
这个程序演示了函数调用和宏调用的区别:函数调用在运行时把参数的值传给函数;宏调用在编译之前把参数的记号传给程序。所以x+2的平方会算错
#include <stdio.h>
#define SQUARE(X) X*X //SQUARE是宏标识符, X是宏参数,X*X是替换列表
#define PR(X) printf("The result is %d.\n", X)
int main()
{
int x = 5;
int z;
printf("x = %d\n", x);
z = SQUARE(x);//宏调用
printf("Evaluating SQUARE(x):");
PR(z