代码之家  ›  专栏  ›  技术社区  ›  Some Name

用UB打印的宏函数

  •  1
  • Some Name  · 技术社区  · 6 年前

    我正在学习如何使用宏函数,现在面临一些(很可能是未定义的)行为。下面是一个例子:

    #include <stdio.h>
    
    #define FOO(a, b) { \
        printf("%s%s\n", #a #b); \
    } \
    
    int main(int argc, char * argv[]){
        { printf("%s%s\n", 1 2); } //compile error
        FOO(1, 2);                 //prints 12 with some garbage
    }
    

    Demo1

    Demo2

    我很可能正在经历UB,但是深入了解 N1570 对此没有给出明确的解释。我发现最接近这个的东西是 5.1.1.2(p4) :

    执行预处理指令,扩展宏调用, 然后执行pragma一元运算符表达式。 如果符合通用字符名称语法的字符序列是 由令牌连接(6.10.3.3)生成,行为未定义。

    可能令牌 "1" "2" 我们连在一起产生了ub,但我不确定。

    2 回复  |  直到 6 年前
        1
  •  5
  •   Lundin    6 年前

    FO扩展到 printf("%s%s\n", "1" "2") . 字符串文本在预处理期间连接,生成 printf("%s%s\n", "12") .

    这不是对printf和ub的正确调用。本标准的相关部分如下:

    7.21.6.1 fprintf功能

    2…如果格式的参数不足,则行为未定义。

        2
  •  6
  •   gsamaras    6 年前

    可能令牌“1”“2”连接在一起产生ub,但我不确定。

    你说得对。

    “1”和“2”变为“12”,并转到第一个 %s 在里面 printf() . 然后,第二个 %s 没有要处理的内容,因此是垃圾值。

    编译器警告也同意(当然):

    prog.cc:4:12: warning: format '%s' expects a matching 'char*' argument [-Wformat=]
        4 |     printf("%s%s\n", #a #b); \
          |            ^~~~~~~~
    prog.cc:9:5: note: in expansion of macro 'FOO'
        9 |     FOO(1, 2);                 //prints 12 with some garbage
          |     ^~~
    prog.cc:4:16: note: format string is defined here
        4 |     printf("%s%s\n", #a #b); \
          |               ~^
          |                |
          |                char*
    

    在宏中,更改:

    printf("%s%s\n", #a #b);
    

    对此:

    printf("%s%s\n", #a, #b);
    

    正如@blaze评论的那样,逗号在哪里起作用。 Live Demo

    注:对于硬编码 Primff() 调用Work,您需要生成1和2个字符串;使用逗号是不够的。例子: printf("%s%s\n", "1", "2"); .