函数参数中前置递增和后置递增的操作顺序是什么?

9

我有一些C代码:

main()
{
    int a=1;
    void xyz(int,int);

    xyz(++a,a++);     //which Unary Operator is executed first, ++a or a++?

    printf("%d",a);
}
void xyz(int x,int y)
{
    printf("\n%d %d",x,y);
}

函数xyz有两个参数传入,分别是++aa++。能否有人解释一下操作顺序以解释结果?

上述代码根据使用的编译器不同会打印出"3 13"或"2 23"。


1
如果您在示例程序中使用不同的变量,可能会更清晰。此外,您应该在要打印的值之后放置“\n”,而不是之前。这将当前打印出“2 23”。 - DevinB
你应该尝试一些更清晰易懂的东西。那个语法对于人类来说相当奇怪。让代码简单化,不要试图编写复杂的东西。 - INS
4个回答

28

嗯,对于你的示例代码有两件事需要考虑:

  1. 函数参数的求值顺序是未指定的,所以++aa++哪个首先求值取决于具体实现。
  2. 在没有序列点分隔两次修改之间修改a的值会导致未定义行为。因此,你的代码结果是未定义的。

如果我们简化你的代码并消除未指定和未定义的行为,那么我们可以回答这个问题:

void xyz(int x) { }

int a = 1;
xyz(a++); // 1 is passed to xyz, then a is incremented to be 2

int a = 1;
xyz(++a); // a is incremented to be 2, then that 2 is passed to xyz

在第二种情况下,a 在函数调用之前被更新了吗?我知道 ++a 的结果是 2,这也是传递给 xyz 的值,但我的理解是副作用不一定会在函数调用之前应用。 - John Bode
3
@John: 是的,函数调用时,在对所有参数求值之后但在函数被调用之前,存在一个序列点。 - James McNellis

9

引用Kernighan & Ritchie,第2.12章:

The order in which function arguments are evaluated is not specified, so the statement

printf("%d %d\n", ++n, power(2, n)); /* WRONG */

can produce different results with different compilers, depending on whether n is incremented before power is called. The solution, of course, is to write

++n;
printf("%d %d\n", n, power(2, n));

Function calls, nested assignment statements, and increment and decrement operators cause ``side effects'' - some variable is changed as a by-product of the evaluation of an expression. In any expression involving side effects, there can be subtle dependencies on the order in which variables taking part in the expression are updated. One unhappy situation is typified by the statement

a[i] = i++;

The question is whether the subscript is the old value of i or the new. Compilers can interpret this in different ways, and generate different answers depending on their interpretation. The standard intentionally leaves most such matters unspecified. When side effects (assignment to variables) take place within an expression is left to the discretion of the compiler, since the best order depends strongly on machine architecture. (The standard does specify that all side effects on arguments take effect before a function is called, but that would not help in the call to printf above.) The moral is that writing code that depends on order of evaluation is a bad programming practice in any language. Naturally, it is necessary to know what things to avoid, but if you don't know how they are done on various machines, you won't be tempted to take advantage of a particular implementation.


0

函数中一元运算符的计算顺序:

#include <stdio.h>

void xyz(int x, int y) {
    printf("x:%d y:%d ", x, y);
}

main() {
    int a;
    a=1;    xyz(++a, a);        printf("a:%d\n", a);
    a=1;    xyz(a, a++);        printf("a:%d\n", a);
    a=1;    xyz(++a, a++);      printf("a:%d\n", a);
}

会输出

x:2 y:2 a:2
x:2 y:1 a:2
x:3 y:1 a:3

在我的系统上,这表明函数的第二个参数先被评估。您不应该依赖于函数参数的评估顺序。它没有定义,因此在不同的系统上会有所不同。
不过,您能找到一个很好的例子来说明这种行为,做得很好。

-2

对于一元运算符,有前缀递增 (++i) 和后缀递增 (i++)。对于前缀递增,要递增的值将在操作之前添加。例如:

#include <iostream>
using namespace std;

void main()
{
    int i = 0;
    cout << ++i;
}

在这种情况下,输出将是1。变量“i”在任何其他操作之前被增加了1的值,即“cout << ++i”。
现在,如果我们在同一个函数中进行后增量:
#include <iostream>
using namespace std;

void main()
{
    int i = 0;
    cout << i++;
}

输出结果将只有0。这是因为递增操作会在运算后发生。但是,如果您想了解如何将它们作为参数传递,下面是具体步骤:

#include <iostream>
using namespace std;
// Function Prototypes
void PrintNumbers(int, int);

void main()
{
    int a = 0, b = 0;
    PrintNumbers(++a, b++);
}

void PrintNumbers(int a, int b)
{
    cout << "First number: " << a << endl;
    cout << "Second number: " << b << endl;
}

当将这些变量作为参数传递时,输出将为:
 First number: 1
 Second number: 0

希望这有所帮助!


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