C——预处理器(Preprocessor)和宏替换(Macro Substitution)以及其他特性的使用和注意事项

C语言的预处理器(Preprocessor)理论上是编译的第一步,通过预处理器来提供了一些特性,例如宏、使用##串联参数、条件包含(Conditional Inclusion)等。

宏替换(Macro Substitution)

C语言在预处理器中提供了宏替换(Macro Substitution)的使用。宏的作用域是从#define到文件结束。宏最简单的定义格式如下:

#define		name	replacement text

如果后续代码出现了name,那么就会用replacement text的内容去替换name。但是需要注意的是,这个替换只可以替代token(标记),不能替代被引用字符串中的一部分。举个例子来说明一下这个问题,假设name部分为MAXVAL,如果后面我们使用printf("MAXVAL")或者出现MAXVALUE,都是不会发生替换的。

这里的name部分可以按照变量的格式来写,也可以带参数(只要参数能都是同样的类型,那么宏能使用任何的数据类型);replacement text的部分可以是整数、浮点数、布尔值、一串代码甚至调用其他之前定义好的宏。例如:

#define max(A, B) ((A) > (B) ? (A) : (B))

尽管这个宏看起来很像函数调用,但是max(A, B)使用的时候会扩展成内连代码(也就是编译的时候,编译器会在这写上这写代码,然后编译,而不是调用一个函数)。

而且需要注意的是,这个地方有个“陷阱”,就是这个宏在使用的时候会判断两次。所以需要注意,宏在使用的时候带参数,会运行两次。尽管如此,这个“陷阱”也有好处,由于会自动多运行一次,这会减少代码的运行时间。

通常我们定义一个宏只需要一行代码,但是如果需要定义比较长的代码的情况下,需要在每一行的结束写上\来表示这行结束了,并且继续。举个例子,我们来交换t类型的xy两个参数的值:

#include <stdio.h>

#define swap(t, x, y) { t c;\
	c = y;\
	y = x;\
	x = c;} 

int main()
{
	int x = 1;
	int y = 2;
	swap(int, x, y);
	printf("x is %d, y is %d\n", x, y);
	return 0;
}

我们可以看到#define的每一行最后都是以反斜杠\结尾,然后再进行下一行。由于这里反斜杠已经被用于表示每行的结束,如果想使用反斜杠\,就使用两个反斜杠\\。由于双引号"也可以表示字符串的开始或者结尾,也可以结束#define,所以我们想使用双引号"的时候就使用一个反斜杠和一个双引号\"来表示。

串联参数

除此之外,C还提供了一些预操作器中的特性。
预操作符##提供了一种方式,在宏扩展(也就是使用的时候)来串联一些参数(将其串联成一个字符串,并且忽略##及周围的空格)。举个例子:

#define		paste(f, b)		f ## b

那么paste(program, 1)的就会表示program1

##嵌套比较神奇,所以不建议使用嵌套。
不过这里还是解释一下##嵌套为什么神奇。我们继续上面的代码,这次我们这样使用:paste(paste(1, 2), 3)。由于paste(paste(1, 2), 3)是从来没被定义过的,所以这时候按照我们之前定义的,第一次结果变成了paste(1, 2)3,也就是说代码把paste(1, 2)当作一个参数和3串联在一起。然后由于)3不是一个合规的表示(第一个参数的最后一个标记和第二个参数的第一个标记串联在一起,跳过了逗号。这里指的第几个参数是指的原本最外部的宏的参数),也就是这里不符合之前定义的样式,所以##制止了第二次扩展。
不能使用嵌套的话,可以定义一个新的宏来调用这个宏。

条件选择(Conditional Inclusion)

条件选择就是在#define的部分使用的if-else,语法稍有不同:
使用#if来做第一个判断;#elif进行下一个判断,等同于if-else语句中的else if#endif表示判断部分结束。
if-else语句一样,通过判断后面的式子的值是否为0,进而判断真假。如果是非0的值,则为真,执行#if#elif或者#endif的代码;如果值是0,就跳过这部分。

条件选择的好处有两个:

  1. 可以避免重复定义宏
  2. 可以通过代码,让每个文件自己处理自己依赖的头文件,不用使用者自己去处理相互依赖的关系。

希望能帮到有需要的人~

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值