C语言printf格式符多于参数的后果?同事谜题程序编译运行疑问
C语言printf相关问题答疑
问题1:printf格式标记数量多于传入参数数量时的后果
哎,这个坑我早年写代码时踩过!当printf里的格式占位符(比如%d、%s这类)数量比你实际传入的参数多的时候,C标准定义这种行为是未定义行为(Undefined Behavior)。说白了就是,程序可能会出现各种诡异情况:比如输出一堆乱码、直接崩溃,甚至看起来“正常运行”但背地里破坏了其他内存数据——完全没规律可言。
原因其实很好理解:printf会按照格式符的要求,从栈里依次读取对应类型的数据。如果参数不够,它就会继续往栈的更深区域读取内存里的垃圾值,这些值是完全不可预测的,所以输出结果根本没法保证。举个简单例子,如果你写printf("%d %d", 42);,第二个%d输出的就是栈里某个随机数,运气差的话甚至会导致程序直接挂掉,具体表现全看你的系统和编译器。
问题2:包含多个自增自减的printf程序为何能编译并运行
哈哈,这题我在论坛上见过好多次了!先拆解来看:
为什么能编译?
C语言编译器默认不会严格校验printf的格式符数量和传入参数数量是否匹配(除非你开启了像-Wall或-Wformat这类严格警告选项)。只要你传入的参数类型和格式符要求的类型匹配(这里都是int类型,对应%d),语法上就完全合法,编译器自然会通过编译。
为什么能运行,但结果不可靠?
这里藏着两个大坑:
- 首先,你看代码里
printf有6个%d,但只传了5个参数——这就回到了第一个问题的情况,最后一个%d会读取栈里的垃圾数据,属于未定义行为。 - 更关键的是,参数列表里的
a++, ++a, a++, --a, ++a都是带有副作用的表达式(会修改a的值)。而C标准没有规定函数参数的求值顺序——也就是说,编译器可以按照任何顺序来计算这些表达式的值:有的从左到右算,有的从右到左算,甚至乱序计算。
举个例子,假设编译器从右往左求值:
- 先算
++a,a从5变成6,取6作为参数; - 再算
--a,a变回5,取5作为参数; - 接着算
a++,取当前的5,然后a变成6; - 再算
++a,a变成7,取7作为参数; - 最后算
a++,取7,a变成8; - 最后一个
%d读取栈里的垃圾值。
但如果编译器从左往右算,结果会完全不同。而且不同编译器、不同优化级别下,求值顺序都可能不一样,所以这个程序的运行结果完全不可预测,属于典型的未定义行为。
内容的提问来源于stack exchange,提问作者ajiraj2411
相关产品推荐
相关产品推荐

