• [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章:通用字符名称)。
  • 相关阅读:
    nginx 配置文件详解
    nginx的location匹配规则
    mysql常用函数
    jquery封装的ajax请求
    docker
    in与exists和not in 与 not exists的区别
    mysql授权
    线程池
    springboot+rediscluster
    常用网址
  • 原文地址:https://www.cnblogs.com/yiyide266/p/11691641.html
Copyright © 2020-2023  润新知