C day16 预处理器 (一)

在这里插入图片描述
在这里插入图片描述在这里插入图片描述

预处理器

在这里插入图片描述

预处理指令从#开始,到后面的第一个换行符为止。所以只可以占据一行

预处理指令的有效范围是定义处到文件结尾。如果宏通过头文件引入,则宏的作用域是#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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值