我正在学习如何使用宏函数,现在遇到了一些(很可能是未定义的)行为。这是一个示例:
#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
}
我很可能正在经历UB,但是深入研究N1570并没有给出明确的解释。我发现与此最接近的是5.1.1.2(p4)
:
执行预处理指令,扩展宏调用, 和_Pragma一元运算符表达式将被执行。 如果与通用字符名称的语法匹配的字符序列为 由令牌级联(6.10.3.3)产生,行为未定义。
可能将令牌"1" "2"
连接在一起产生了UB,但我不确定。
答案 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 ...如果格式的参数不足,则行为未定义。