代码之家  ›  专栏  ›  技术社区  ›  matt

试图理解C预处理器

  •  6
  • matt  · 技术社区  · 14 年前

    #define PART1PART2 works
    #define STRINGAFY0(s) #s
    #define STRINGAFY1(s) STRINGAFY0(s)
    

    案例1:

    #define GLUE(a,b,c) a##b##c  
    STRINGAFY1(GLUE(PART1,PART2,*))
    //yields
    "PART1PART2*"
    

    #define GLUE(a,b) a##b##*
    STRINGAFY1(GLUE(PART1,PART2))
    //yields
    "works*"
    

    案例3:

    #define GLUE(a,b) a##b
    STRINGAFY1(GLUE(PART1,PART2*))
    //yields
    "PART1PART2*"
    

    编辑: 我目前认为,在扩展宏时,预处理器的工作方式如下: 第一步: -把尸体带走 -删除##运算符周围的所有空格 -如果找到与参数名称匹配的标识符,请分析字符串: -如果它不在##运算符旁边,请首先对参数的值运行整个解释过程,然后用该结果替换标识符。 (忽略stringafy单个'#'case atm)

    第二步:

    现在,从这一点来看,我认为所有3种情况都应该产生完全相同的结果字符串:

    因此在第2步之后

    作品*

    2 回复  |  直到 8 年前
        1
  •  3
  •   Jens Gustedt    8 年前

    案例1和案例2没有定义的行为,因为您很想粘贴 * PART1PART2 (或者只是 PART2 * . 在您的例子中,这可能会无声地失败,这是未定义事物时可能出现的结果之一。代币 第1部分第2部分 *

    /usr/bin/gcc -O0 -g -std=c89 -pedantic   -E test-prepro.c
    test-prepro.c:16:1: error: pasting "PART1PART2" and "*" does not give a valid preprocessing token
    "works*"
    

    总结一下你的案例1有两个问题。

    • 粘贴两个没有结果的标记
    • 评估顺序 ## 操作人员

    在案例3中,编译器给出了错误的结果。应该的

    1. 评估参数 STRINGAFY1
    2. GLUE
    3. 胶水 结果 PART1PART2*
    4. 结果是 works*
    5. 然后传递给 字符串1
        2
  •  1
  •   Michael Dorgan    14 年前

    它做的正是你让它做的。第一个和第二个获取传入的符号名,并将它们粘贴到一个新符号中。第三个取2个符号并粘贴它们,然后您自己将*放入字符串中(最终将计算为其他值)

    当然还有一个问题,你为什么要这样玩弄符号咀嚼的黑暗艺术