【问题标题】:Macro function for printing with UB使用 UB 打印的宏功能
【发布时间】:2019-01-10 07:27:40
【问题描述】:

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

#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,但我不确定。

【问题讨论】:

  • "可能标记 "1" "2" 被连接产生 UB"。这是正确的。对于第一个%s,您会得到一个自动连接的"12",而对于第二个%s,您将一无所有,因此为什么您会为那个打印垃圾。在#a#b 之间尝试printf("%s%s\n", #a, #b);,

标签: c macros printf undefined-behavior


【解决方案1】:

可能标记“1”“2”被连接产生UB,但我不确定。

你是对的。

“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");

【讨论】:

    【解决方案2】:

    FOO 扩展为 printf("%s%s\n", "1" "2")。字符串文字在预处理过程中被连接起来,产生printf("%s%s\n", "12")

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

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

    【讨论】:

    • 那么printf("%s\n", "1" "2"); 的行为是明确定义的?但是我引用的部分呢?
    • @SomeName 是的。您引用的部分完全不相关且随机,它指的是非常特殊的情况,其中使用## 预处理令牌连接 - 这与字符串文字连接完全不同 - 产生“通用字符名称”,例如@987654325 @。通用字符名称是一种罕见的稀有功能,当源代码编辑器不支持时,它允许在源代码中输入字符。它在 6.4.3 中描述。这与你的问题无关。
    • 是的。你的意思是在阶段6. Adjacent string literal tokens are concatenated?
    • @SomeName 是的,# 标记在翻译阶段 4 被转换为字符串文字,但字符串文字连接发生在翻译阶段 6。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-10
    • 1970-01-01
    • 2012-09-15
    • 2020-10-10
    相关资源
    最近更新 更多