C 在printf函数格式中,标签高于args会发生什么?

C 在printf函数格式中,标签高于args会发生什么?,c,printf,C,Printf,一位同事给了我一个难题,我无法理解这个C程序实际上是如何编译和运行的 int main() { int a=5; printf("%d %d %d %d %d %d",a++,++a,a++,--a,++a); return 0; } 尽管C语言规范没有定义这种行为,但考虑到最常见的C实现,我们可以猜测会发生什么 printf是一个可变函数,这意味着它所使用的参数数量可能会有所不同。通常,参数的数量由格式字符串决定,只要格式字符串需要,函数的实现将继续从堆

一位同事给了我一个难题,我无法理解这个C程序实际上是如何编译和运行的

int main()  
{  

    int a=5;  
    printf("%d %d %d %d %d %d",a++,++a,a++,--a,++a);


return 0;  
}

尽管C语言规范没有定义这种行为,但考虑到最常见的C实现,我们可以猜测会发生什么

printf
是一个可变函数,这意味着它所使用的参数数量可能会有所不同。通常,参数的数量由格式字符串决定,只要格式字符串需要,函数的实现将继续从堆栈中获取参数

由于有6个
%d
,只有5个参数,因此该函数将从堆栈中额外获取一个4字节的值,将其解释为整数,并将其打印出来


当然,这些都不能保证。这个程序已经打破了规则,鼻魔是一个有效的可能性。但是我认为基于堆栈的一部分获取垃圾输出是一个合理且可能的结果。

这在ISO标准中有介绍
C11 7.21.6.1 fprintf函数/2
的状态非常清楚,
printf()
只是
fprintf(stdout)
的简写:

fprintf
函数在
format
指向的字符串控制下,将输出写入
stream
指向的流,该字符串指定后续参数如何转换为输出如果格式的参数不足,则行为未定义。如果格式已用尽,而参数仍保留,则会计算多余的参数(一如既往),但会忽略多余的参数

那么,接下来会发生什么呢!毕竟,这就是“未定义”的含义


你需要记住,任何事情都有可能在你竭尽全力的情况下仍然有效。由于它是未定义的,编译器甚至可以自由地假设您不知道需要什么,只需从字符串中删除最终的格式说明符。它还可以格式化您的硬盘,并通过您的音响系统播放
dericious_lough.mp3
文件:-)

,这是多层次的。首先也是最重要的。未定义的行为并不意味着编译器会出错,但是一个好的行为可能会警告某些UB(比如传递几个格式参数)。这取决于第六个整数参数是在寄存器中传递还是在堆栈中传递。好奇:Windows的64位约定与Linux/FreeBSD/Solaris不同。在Windows上,只有四个int/指针参数在寄存器中传递,但在Linux/等上,有六个参数被传递。