使用UB

时间:2019-01-10 07:27:41

标签: c macros printf undefined-behavior

我正在学习如何使用宏函数,现在遇到了一些(很可能是未定义的)行为。这是一个示例:

#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 个答案:

答案 0 :(得分: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

注意:对于要进行硬编码的printf()调用,您需要输入1和2个字符串。使用逗号是不够的。例如:printf("%s%s\n", "1", "2");

答案 1 :(得分:5)

FOO扩展为printf("%s%s\n", "1" "2")。字符串文字在预处理期间被串联,产生printf("%s%s\n", "12")

这不是对printf和UB的正确调用。该标准的相关部分是:

  

7.21.6.1 fprintf函数
  ...
  2 ...如果格式的参数不足,则行为未定义。