• 一个C语言宏展开问题


    转自一个C语言宏展开问题


    一个令人比较迷惑的问题,学C语言好多年,今天终于搞明白,记之。
    -------------------------------------------------------------
    #define cat(x,y)  x ## y
    #define xcat(x,y) cat(x,y)
    cat(cat(1,2),3) //为什么不是 123?
    xcat(xcat(1,2),3) //结果为什么是 123?
    -------------------------------------------------------------

    要解答这个问题,首先看一下预处理过程的几个步骤:
    1) 字符集转换(如三联字符)
    2) 断行连接 /
    3) 注释处理, /* comment */,被替换成空格
    4) 执行预处理命令,如 #include、#define、#pragma、#error等
    5) 转义字符替换
    6) 相邻字符串拼接
    7) 将预处理记号替换为词法记号

    在这里主要关注第4步,即如何展开函数宏。(其他步骤和本文关系不大,但对于理解预处理过程是十分重要的)宏函数替换展开,规则可简单总结如下:在展开当前宏函数时,如果形参有#(字符串化操作)或##(记号连接操作)则不进行宏参数的展开,否则先展开宏参数,再展开当前宏(就像先计算函数中的参数,然后调用函数一样)。回头看最初的问题,则两个宏展开过程如下:
    -------------------------------------------------------------
    cat(cat(1,2),3)
    => cat(1,2) ## 3    // cat(x,y)  x##y参数前有##操作,参数不展开
    => cat(1,2)3        // K&R中说,)3 是一个不合法记号,不展开
    -------------------------------------------------------------
    xcat(xcat(1,2),3)
    => xcat(cat(1,2),3)  //xcat(x,y) cat(x,y)参数前无#,##操作,则先展开参数
    => xcat(1 ## 2,3)
    => xcat(12,3)
    => cat(12,3)
    => 12 ## 3
    => 123
    -------------------------------------------------------------

    有兴趣的话,可以看下面一些宏替换问题:
    -------------------------------------------------------------
    #define X 3
    #define Y X*2
    #undef  X
    #define X 2
    int z=Y; // z = 4
    -------------------------------------------------------------
    #define hash_hash # ## #
    #define mkstr(a) # a
    #define in_between(a) mkstr(a)
    #define join(c, d) in_between(c hash_hash d)
    char p[] = join(x, y); // 等同于char p[] = "x ## y";
    -------------------------------------------------------------
    #define connect(x) i ## x
    #define connect2(x) connect(x)
    #define s(a) a
    #define is(a) a
    int i2=2;
    printf("%d/n", connect(s(1)) );/*connect的形参x是##的操作数,故不展开它对应的实参s,直接连接记号i和实参序列s(1),得到is(1),继续替换得到最后结果1*/
    printf("%d/n", connect2(s(2)) );/*connect2的形参x不是##的操作数,故先展开它对应的实参s,再用展开结果2替换之,得到connect(2),继续替换得到最后结果i2*/
    -------------------------------------------------------------
    #define TEST(a,b) /
    do {/
    printf(#a "=%d/n", a); /
    printf(#b "=%d/n", b); /
    } while (0)


  • 相关阅读:
    PHP函数篇详解十进制、二进制、八进制和十六进制转换函数说明
    TP5安装workerman版本的坑
    下载git2.2.1并将git添加到环境变量中
    RedHat安装git报错 expected specifier-qualifier-list before ‘z_stream’
    Git出现fatal: Unable to find remote helper for 'https'
    ThinkPHP5实现定时任务
    php一行代码获取本周一,本周日,上周一,上周日,本月一日,本月最后一日,上月一日,上月最后一日日期
    git 查看日志记录
    程序员必读之软件架构 读书笔记
    centos7 安装桌面
  • 原文地址:https://www.cnblogs.com/noble/p/4144039.html
Copyright © 2020-2023  润新知