第四章导言处补充内容

这里来讲一下由于篇幅问题没办法讲到的内容

ANSI标准新增的条件编译指令

在旧版本的C中,可能只有以下指令:#ifdef#ifndef#endif

但是新的预处理器新增了一些新东西,例如用于判断条件的#if,还有类似else if#elif,以及#else

这样有什么实际的作用呢,比如说我想根据版本来推送对应的内容,那么我可以这样写:

1
2
3
4
5
6
7
8
#define OS_VERSION 10
#if OS_VERSION >= 10
#include "new_api.h"
#elif OS_VERSION >= 8
#include "old_api.h"
#else
#error "不支持的系统"
#endif

类推一下,可以把上面的系统版本修改为各类系统的名称(例如Window、Linux、MacOS之类的)从而适配不同的设备

通过宏参数创建带引号的字符串的方法

这里指的是在宏定义中,当#紧跟在参数后面时,那么预处理器会自动将这个参数转换为带双引号的字符串

1
2
3
#define STR(x) #x

STR(hello)

上面STR输出的结果为"hello",可以发现带上了双引号

利用这个功能我们可以想到什么?对,就是任何可以用到双引号的地方

举个例子

如果我们想要在输出的时候同时打印变量名和对应的值

那么我们只需要这样写即可:

1
#define PRINT_VAR(x) printf(#x "= %d\n",x)

由于#x输出的结果是一个带双引号的数值,那么对应的,这里也会带上双引号

具体的情况如下:

1
2
3
4
5
6
7
#define PRINT_VAR(x) printf(#x "= %d\n",x)

int main(){
int a = 10;

PRINT_VAR(a);
}

上面例子运行的结果为:a = 10

这里可以看作是这样子的:printf("a" "= %d\n",a)

对宏扩展更加严格

什么叫做对宏扩展更加严格,说白了其实是减少了歧义的发生

其实这个点在之前已经有提到过了,这里再提及一次

1
#define ADD(x,y) x * y

这里如果传入的值为一个数,那当然没问题,可如果x或者y是一个表达式呢?

1
2
3
4
#define ADD(x,y)

// 此处为了方便就省略具体的main了,也就是直接写出语句
ADD(111+222,333);

此时运算顺序是怎么样的?

这条式子实际应该为这样子的:111 + 222 * 333

那么会先运行哪一部分呢?很明显会先运行后面的乘法运算,这样就跟我们想要的结果不太一样了

那么要怎么操作才可以避免这种情况发生呢?其实只需要在给每一个参数加上括号即可,也就是这样子:

1
#define ADD(x,y) ((x) * (y))

加上这个括号之后,会优先运行括号内部的内容,这样就可以有效的避免歧义的发生


还有一个点就是嵌套宏的情况

1
2
3
4
#define A 10
#define B(x) x * 10

B(A);

在实际的编译过程中,会优先把宏展开,也就是把A展开为10,之后再带入B(x)