c++ - 为什么与 printf 未定义行为中的转换说明符不匹配的参数?

标签 c++ c printf undefined-behavior

在 C (n1570 7.21.6.1/10) 和 C++(通过包含 C 标准库)中,向 printf 提供类型与其转换规范不匹配的参数是未定义的行为。一个简单的例子:

printf("%d", 1.9)

格式字符串指定一个int,而参数是一个浮点类型。

这个问题的灵感来自于遇到遗留代码的用户的问题,该代码有大量的转换不匹配显然没有伤害,cf。 undefined behaviour in theory and in practice .

一开始仅仅声明格式不匹配 UB 似乎有些过激。很明显,输出 可能是错误的,这取决于确切的不匹配、参数类型、字节顺序、可能的堆栈布局和其他问题。正如那里的一位评论员指出的那样,这也延伸到后续(甚至之前?)的论点。但这远非一般的UB。就个人而言,除了预期的错误输出之外,我从未遇到过任何其他情况。

为了大胆猜测,我会排除对齐问题。我可以想象的是,提供一个格式字符串使 printf 期望大数据和小的实际参数可能会让 printf 读取堆栈之外的内容,但我对 var args 机制和特定的 printf 实现缺乏更深入的了解详细信息以验证这一点。

我快速浏览了 printf sources , 但它们对不经意的读者来说是相当不透明的。

因此我的问题是:printf 中转换说明符和参数不匹配的具体危险是什么?

最佳答案

printf 只有在正确使用的情况下才能按照标准描述的那样工作。如果使用不当,行为是未定义的。为什么标准要定义错误使用时会发生什么?

具体来说,在某些体系结构上,浮点参数在不同的寄存器中传递给整数参数,因此在 printf 内部,当它试图找到与格式说明符匹配的 int 时,它将在相应的寄存器中查找垃圾。由于这些细节超出了标准的范围,因此除了说它未定义外,没有办法处理这种不当行为。

举一个错误可能有多严重的例子,使用格式说明符 "%p" 但传递浮点类型可能意味着 printf 尝试读取来自未设置为有效值且可能包含陷阱表示的寄存器或堆栈位置的指针,这将导致程序中止。

关于c++ - 为什么与 printf 未定义行为中的转换说明符不匹配的参数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33648596/

相关文章:

c++ - 在 bool 函数中返回 true 或其他内容

c++ - 静态数据成员的类内初始化

使用 x86/x64 C API 的 C# AnyCPU 库 - 打包结构、调用和回调

C:在没有 gcc 警告的情况下找出 typedef 的 % 格式说明符?

c - 在 C 中打印长度为 char 的缓冲区

c# - 在 C 系列中,在一个循环中,为什​​么 "less than or equal to"比 "less than"符号更受欢迎?

C++ 数组中的随机数生成器

c - 如何让程序不断要求用户在C编程中输入值

c - 使用 fprintf 的奇怪 SEGFAULTS

c - 用多行字符串写 printf(@"")