如果用错误的格式字符串调用printf会发生什么?

8
换句话说,一个错误的printf / fprintf十进制整数(%d,%u,%ld,%lld)格式字符串能否导致程序崩溃或导致未定义行为?
考虑以下代码行:
#include <iostream>
#include <cstdio>

int main() {
    std::cout << sizeof(int) << std::endl
              << sizeof(long) << std::endl;

    long a = 10;
    long b = 20;
    std::printf("%d, %d\n", a, b);

    return 0;
}

32位架构的结果:

4
4
10, 20

64位体系结构的结果:

4
8
10, 20

无论如何,程序都会打印出预期的结果。我知道,如果 long 值超过了 int 范围,程序会打印错误的数字 - 这很丑陋,但不影响程序的主要目的 - 除此之外,还可能发生意外情况吗?

1
可能是使用错误的格式说明符会发生什么?的重复问题。 - phuclv
5个回答

11
如果使用错误的格式字符串调用printf,任何事情都可能发生。这是未定义行为! 未定义行为意味着任何事情都可能发生。它可能显示您期望的结果,也可能不是,或者可能崩溃。任何事情都可能发生,您只能责怪自己。

参考资料: c99标准:7.19.6.1: 第9段:如果转换说明符无效,则行为未定义。225)如果任何参数与对应的转换说明符的正确类型不匹配,则行为未定义。

4
你的意思是 char c=1;printf("%d",c); 也是未定义行为吗? - rondino
5
"你唯一能责怪的就是你自己" -- 最后,我在这篇博客文章的结尾部分找到了一个很好的回应;请看“指责程序员”一节。链接在这里:https://eev.ee/blog/2016/12/01/lets-stop-copying-c/。 - Kyle Strand
4
不行,因为在传递给printf()之前,'c'会被提升为'int'。请查看“默认参数提升”。 - Swordfish

3
这是未定义的行为 - 规范中没有告诉编译器设计者(或C库设计者)应该如何处理,因此他们可以做任何事情。
实际上,这是其中一种完全取决于数字解释的情况,最有可能的是,您不会从中获得任何好处。 当您将字符串与整数格式混合使用时,真正糟糕的情况是 - 字符串将作为(奇怪,也许)数字打印出来,但是当数字作为字符串传递时不太可能“工作”- 因为字符串是指向第一个字符的地址的指针 - 并且大多数组成都不是典型系统中的有效指针,因此它会崩溃。
但是没有任何保证。 在您的64位示例中,很明显该数字是“little endian”。 尝试使用0x100000000执行相同的操作,它将打印0 - 因为其余数字丢失了。

2

对的 - printf 依赖于格式字符串来确定要获取的变量的大小和类型。当格式字符串错误时,它可能会尝试获取甚至不存在的变量,造成所有可能的后果。


2

如果使用错误的格式字符串调用printf函数,那么任何事情都可能发生。这是未定义的行为,我们绝不能依赖于未定义的行为。


-3

不要使用printf

printf是C语言时代的遗物,现在已经不再需要了...请改用std::cout和I/O操作符。


1
这通常是一个明智的建议,但它并没有回答问题。 - Alok Save
1
@AlokSave 非常正确,但我认为原帖提出了错误的问题。 - Alex Chamberlain
4
没有错误的问题,只有格式不当和格式正确的问题。忽略问题上的 C++ 标签,这就成为一个完全有效的问题。 - Alok Save
2
在我们的嵌入式代码中,我们使用C++,但不使用iostreams。我们结合自定义日志函数/方法使用snprintf和vsnprintf。因此,printf系列仍然非常相关和有用。还请注意,整个标准C库是旧C时代的遗留物。它被广泛使用、维护,并且对全球大量开发人员仍然有用。 - Craig B

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接