使用 UB 打印的宏功能
Macro function for printing with UB
我正在学习如何使用宏函数,现在遇到了一些(很可能是未定义的)行为。这是一个例子:
#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)
:
Preprocessing directives are executed, macro invocations are expanded,
and _Pragma unary operator expressions are executed. If a character sequence that matches the syntax of a universal character name is
produced by token concatenation (6.10.3.3), the behavior is undefined.
可能令牌 "1" "2"
被连接起来产生 UB,但我不确定。
Probably tokens "1" "2" were concatenated yielding UB, but I'm not sure.
你是对的。
“1”和“2”变成了“12”,走到了printf()
中的第一个%s
。然后,第二个 %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");
.
FOO 扩展为 printf("%s%s\n", "1" "2")
。字符串文字在预处理期间连接起来,产生 printf("%s%s\n", "12")
.
这不是对 printf 和 UB 的正确调用。标准中的相关部分是这样的:
7.21.6.1 The fprintf function
...
2 ... If there are insufficient arguments for the format, the behavior is undefined.
我正在学习如何使用宏函数,现在遇到了一些(很可能是未定义的)行为。这是一个例子:
#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)
:
Preprocessing directives are executed, macro invocations are expanded, and _Pragma unary operator expressions are executed. If a character sequence that matches the syntax of a universal character name is produced by token concatenation (6.10.3.3), the behavior is undefined.
可能令牌 "1" "2"
被连接起来产生 UB,但我不确定。
Probably tokens "1" "2" were concatenated yielding UB, but I'm not sure.
你是对的。
“1”和“2”变成了“12”,走到了printf()
中的第一个%s
。然后,第二个 %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");
.
FOO 扩展为 printf("%s%s\n", "1" "2")
。字符串文字在预处理期间连接起来,产生 printf("%s%s\n", "12")
.
这不是对 printf 和 UB 的正确调用。标准中的相关部分是这样的:
7.21.6.1 The fprintf function
...
2 ... If there are insufficient arguments for the format, the behavior is undefined.