如果在一个函数中使用"return b++",那么"b"的增量会发生什么?

3

在下面的程序中,如果使用 return b++,由于 b++ 是后增量,那么 b 的增量会发生什么情况?

#include<stdio.h>

int foo(int);

int main()
{
   int a=8;
   printf("%d",foo(a));
}

int foo(int a)
{
   static int  b=a*a;
    return b++;
}

编辑

#include<stdio.h>
int foo();

int main()
{
foo();
foo();
}

int foo()
{
    static int b=1;
    printf("%d\n",b);
    return b++;
}

结果

1

2

根据我在编辑时所见,为什么会增加breturn不应该立即退出该函数吗?为什么b在控制权返回到main()之后仍然增加?难道不是所有的活动都应该在return之后结束吗?


1
注意b上的关键字static。这段代码在C编译器中无法通过编译。但在C++编译器中可以,并且行为是"如你所期望的"。 - Mats Petersson
4个回答

5
许多 C (子-)表达式都有一个值和一个副作用。 b++ 的值是在评估表达式之前的 b 的值;它的副作用是将 b 中的值增加一。
因此,表达式 return b++; 返回 b 的先前值并更新 b。 当 b 是 static 时,更新将保留到下一个函数调用; 当 b 是普通的本地变量时,更新会丢失(一个聪明的编译器甚至不会发出代码来更新对象)。

那确实很有帮助。我指的是第一行。 - Thokchom

4

实际上,这段代码无法编译成功,因为 b 的初始化不是一个常量。

由于 b 是静态变量,它本质上是一个全局变量,在 main 函数之前就已经被初始化了,在那个时候变量 a 还不存在。

但如果我们将其作为 C++ 编译,则 b 会在第一次调用 foo 时被初始化,其值为 64。在返回时,b++ 会被递增并存储为 65,但返回值仍然是 64。所以,如果再次调用 foo,它将返回 65(而 b 为 66)。

根据编辑后的代码进行修改:

因此,该代码本质上执行以下操作:

 int temp = b;
 b = b + 1;
 return temp; 

这是C语言定义变量的方式。表达式 x++ 的结果是先前的值 x,但是 x 的值会增加。由于 static 本质上是全局的(但没有名称,因此无法在该函数之外使用),因此该值在调用函数时保持不变,并且在调用 main 函数之前进行初始化。


请检查我的修改后的程序。第一个程序没有很好地表达我的意思。为什么要增加 b 的值? - Thokchom
在一个函数中,一旦遇到return,难道不是所有的活动都应该结束吗?foo()不应该返回b并将控制权传递给main(),而不是增加b吗? - Thokchom
不,return b++; 会执行 b++,然后返回从中得到的值 - 这是 b 的“旧”值。 - Mats Petersson

3

return b++;等同于: int c = b; b = c + 1; return c;

回答您的新问题: - 在返回之前,函数确实会退出,但需要先评估表达式b++。评估这种表达式将导致b被递增。 - 所有活动在函数返回后都结束,但是b被声明为静态变量,其值在函数的后续执行中保持不变。

为了让您更容易理解,后置递增就像以下函数

int postincrement(int& x) {
    int y = x;
    x = x + 1;
    return y;
}

(当然,如果编译器发现增加b没有任何效果,则可以优化b ++,但在这种情况下它确实具有影响(增加静态int b ),因此不能被优化掉。)

你错了。根据MVP的回答,增量永远不会发生,因为函数在return b++之后返回控制权。增量从未发生过。 - Thokchom
2
b是一个静态变量,因此增量将会发生,因为它将在对foo的调用之间保持其状态。 - Steve
@Steve 函数执行 return 后不是所有操作都应该停止吗?例如如果在 return 之后有一个 printf(),它将会被忽略。那么为什么这个递增操作还会发生呢? - Thokchom
2
如果您使用return printf("hi!\n");,那么这将被执行。表达式被评估,并且会发生任何可见的副作用。(任何不能被观察到的表达式副作用都可以被编译器优化掉...但不是必须的。) - cHao
也许这样做可以更容易理解,但它并不是一个特别有用的答案。这个答案可能会让学生误以为C语言有传递引用的功能,但实际上并没有。@javic也许你可以用预处理器宏来解释同样的概念。例如:#define post_increment(x) ((x = x + 1) - 1) - autistic
显示剩余6条评论

1
这个后置增量完全没有意义 - 因为变量b的作用域是局部的,它的增加值会在return之后被丢弃。如果你的编译器很聪明,它很可能会将其优化掉。

b的增量从未发生,对吧?那么Javic的答案不是错了吗? - Thokchom
这取决于编译器的智能程度。很可能不会发生。但是,如果 b 不是 int,而是通过引用传递的某个对象,并且重新定义了 operator++,那么这将产生一些副作用。 - mvp
你们两个都错了,上面的代码不能编译成C语言,因为a不是一个常量值。我正在撰写一篇答案,同时解释C++解决方案,其中该代码是有效的。 - Mats Petersson
@MatsPetersson 请检查我即将发布的编辑。它似乎与您所说的一致,而且与之前的答案相反。 - Thokchom

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