[C]预处理指令

一、预处理指令在编译阶段就处理了,所以编译成才后运行的这个阶段已经是预处理后的结果,例如指令

#define BUFFSIZE 4096

      的预处理方式是把代码出现有BUFFSIZE的地方都替换为4096;

      下面的例子,test会正确打印BUFFSIZE,跟作用域无关:

#include <stdio.h>

void test(void);

int main(void)
{
    test();
    #define BUFFSIZE 4096
}

void test(void){
    printf("%d
", BUFFSIZE);//输出4096
}

反而跟编译顺序有关,把BUFFSIZE定义放在定义test的行数之下,编译器就会报错:

#include <stdio.h>

void test(void);
void test(void){
    printf("%d
", BUFFSIZE);
}

int main(void)
{
    test();
    #define BUFFSIZE 4096
}

报错:

c72.c: In function ¡®test¡¯:
c72.c:7:17: error: ¡®BUFFSIZE¡¯ undeclared (first use in this function)
  printf("%d
", BUFFSIZE);
                 ^
c72.c:7:17: note: each undeclared identifier is reported only once for each function it appears in

二、遇到带参数的宏,当参数也是宏的时候,作为参数的宏会优先展开。

#include <stdio.h>

#define ONE_CHAR  'a'

void main(void)
{
    putchar(ONE_CHAR);
}

示例中putchar也是宏,它声明在stdio.h里,形式类似于这样

#define putchar(x)  putc(x, stdout)

有一点需要注意的是,预处理器只会将宏当作字符串展开,并不会给变量做其他操作(除非使用了字符串化运算符操作,参考《C语言核心技术》第14章:字符串化运算),所以宏ONE_CHAR的代替字符串中必须包含单引号,展开后代码就恰好给putchar传入了一个字符常量。

去掉引号的代码会引起报错:

#include <stdio.h>

#define ONE_CHAR a

void main(void)
{
    putchar(ONE_CHAR);
}
c81.c: In function ¡®main¡¯:
c81.c:3:18: error: ¡®a¡¯ undeclared (first use in this function)
 #define ONE_CHAR a
                  ^

 原因是展开宏后是这样的:

putc(a,  stdout);

表达式中,a被视为标识符,因为编译器找不到标识符a的声明,所以抛出以上报错信息。

声明一个a自变量,就没问题了:

#include <stdio.h>

#define ONE_CHAR a

void main(void)
{
    char a = 'a';
    putchar(ONE_CHAR);//打印出a
}

三、可选性自变量的宏

在C99标准下,可以定义有省略符号(...)的宏,省略符号必须放在最后面,表示“可选的”。

当调用时,预处理器会将“所有可选性自变量”,连同分隔它们的逗号,聚集在一起当作一个自变量。在代替文字当中,把__VA_ARGS__这个标识符替换成这个自变量。

宏调用的时候,必须有“至少一个”参数。

例如,定义一个打印日志到文件的宏:

#include <stdio.h>

#define printLog(...) fprintf(fp, __VA_ARGS__)

void main(void)
{
    FILE* fp = fopen("./c81.txt", "a");
    int intVar = 5;
    printLog("%s: intVar = %d
", __func__, intVar);
}

printLog宏展开后,类似于这种形式:

fprintf(fp, "%s: intVar = %d
", __func__, intVar);

 四、字符串化运算符:#

在宏的代替字符内容中的参数前面增加#,会把一个这个参数转换成字符串。

#include <stdio.h>
#include <math.h>

#define printDBL(exp) printf("express:"#exp " = %f
", exp)

void main(void)
{
    printDBL( 4 * atan(1.0) );
}

输出:

express:4 * atan(1.0 ) = 3.141593

预处理器会把对应的自变量放在一对双引号中,形成一个字符串字面值。自变量中的所有字符本身维持不变,但是下面是例外:

  • 在记号之间,如果有任何空白(whitespace)字符序列,则会被替换成一个空格(space)字符。
printDBL( 4 *         atan(1.0    ) );//就算把以上例子改为这样,输出也是一样的,因为所有连续不连续的空白字符都转换成一个空格了
  • 自变量中每个双引号(")的前面会放置一个反斜杠(backslash)。
  • 自变量中每个反斜杠的前面放置一个反斜杠。但如果此反斜杠是通用字符名称的一部分,则不会在前面放置一个反斜杠(见《C语言核心技术》第1章:通用字符名称)。
原文地址:https://www.cnblogs.com/yiyide266/p/11691641.html