解释printf中的评估顺序

时间:2012-10-18 17:21:06

标签: c printf

main()
{
    int i=5;
    printf("%d%d%d%d%d%d",i++,i--,++i,--i,i);
}

输出是45545,但我不知道它是如何工作的。有人说函数调用中的参数从左到右被压入堆栈。

5 个答案:

答案 0 :(得分:19)

未指定函数参数的评估顺序。

来自c99标准:

  

6.5.2.2函数调用

     

10 /函数指示符的评估顺序,实际   参数和实际参数中的子表达式是   未指定,但在实际调用之前有一个序列点。

然而,这只是问题的一部分。另一件事(实际上更糟糕,因为它涉及未定义的行为)是:

  

6.5表达式

     

2 /在上一个和下一个序列点之间有一个对象   它的存储值最多只能通过评估一次修改   表达。此外,先前值应只读取   确定要存储的值。

在我们的例子中,所有参数评估仅在2个序列点之间:前一个;和输入函数之前的点,但是在评估了所有参数之后。你最好不要写这样的代码。

C标准在某些地方相当宽松,为编译器可能做的优化留出了空间。

答案 1 :(得分:4)

传递函数参数的顺序未在标准中定义,并由编译器使用的calling convention确定。 我认为在你的情况下,使用cdecl调用约定(许多C编译器用于x86架构),函数中的参数从右到左进行评估。

答案 2 :(得分:3)

两点:

  • 函数参数以未指定的顺序计算。这允许编译器根据喜好进行优化。
  • 您的特定参数会调用未定义的行为。您不允许在序列点之前多次修改i

答案 3 :(得分:3)

此函数调用是未定义的行为:

printf("%d%d%d%d%d%d",i++,i--,++i,--i,i);

在两个序列点之间多次修改对象是C中未定义的行为。

它也是未定义的行为,因为您有6个转换规范,但格式只有5个参数。

答案 4 :(得分:1)

printf参数的评估顺序未指定。除其他外,它取决于您正在使用的系统的调用约定。此外,这也是一种未定义的行为,因为您在没有任何序列点的情况下多次修改i。顺便说一句,有一个缺失的论点。