你以前试过这个吗?
static void Main(string[] args)
{
int x = 10;
x = x++;
Console.WriteLine(x);
}
输出:10。
但是
static void Main(string[] args)
{
int x = 10;
x++;
Console.WriteLine(x);
}
输出:11。
有人可以解释为什么吗?
答案 0 :(得分:73)
X ++将增加该值,但随后返回其旧值。
所以在这种情况下:
static void Main(string[] args)
{
int x = 10;
x = x++;
Console.WriteLine(x);
}
你只有11点的X,然后它回到10,因为10是(x ++)的返回值。
您可以为相同的结果执行此操作:
static int plusplus(ref int x)
{
int xOld = x;
x++;
return xOld;
}
static void Main(string[] args)
{
int x = 10;
x = plusplus(x);
Console.WriteLine(x);
}
值得一提的是,如果您愿意,您的预期结果为11:
static void Main(string[] args)
{
int x = 10;
x = ++x;
Console.WriteLine(x);
}
答案 1 :(得分:57)
在作业x = x++
中,首先提取x
的旧值,用于评估右侧表达式,在本例中为“x”;然后,将x
递增1.最后,通过赋值语句将表达式求值(10)的结果赋值给x
。
也许等效的代码会使困境变得清晰:
var tmp = x;
x++;
x = tmp;
这相当于C#中的x = x++
代码。
答案 2 :(得分:15)
x ++的行为是增加x,但在增量之前返回值 。由于这个原因,它被称为后增量。
所以x = x ++;简单地说就是
<强> 1。返回值,然后
<强> 2。增量x ,然后
第3。将x的原始值(在步骤1中返回)分配给x 。
答案 3 :(得分:11)
x = 10
x = ++x
x
最终会等于11。
答案 4 :(得分:7)
x++;
执行以下操作:
int returnValue = x;
x = x+1;
return returnValue;
如您所见,保存原始值,增加x,然后返回原始值。
最终做的是将值保存在某处,设置x等于11,然后返回10,这会导致x被设置回10.注意x实际上在几个周期内变为11(假设没有编译器优化)。
答案 5 :(得分:4)
这不是直接回答问题,但为什么世界上任何人都会使用
x = x++;
它完全违背了后增量/预增量运算符的目的。
答案 6 :(得分:3)
你可以这样想:
int x = 10;
X是一个容器,包含一个值10。
x = x++;
这可以细分为:
1) increment the value contained in x
now x contains 11
2) return the value that was contained in x before it was incremented
that is 10
3) assign that value to x
now, x contains 10
现在,打印x
中包含的值Console.WriteLine(x);
并且,毫不奇怪,它打印出10。
答案 7 :(得分:2)
根据定义,x ++返回x的值,然后递增x。
http://blogs.msdn.com/lucabol/archive/2004/08/31/223580.aspx
答案 8 :(得分:1)
你做的第一件事叫做“后增量”,意思是
int x = 10;
x++; //x still is 10
Console.WriteLine(x); //x is now 11(post increment)
所以你分配x = x ++的那一刻; x仍然是10你能做什么,如果你需要x在这一行是11写++ x(想想它的前增量纠正我,如果我错了)...或者右x ++;而且比x = x ++;
问题,它是依赖于行还是声明意味着它会在之后递增; ?
答案 9 :(得分:1)
我知道有很多答案,而且是一个被接受的答案,但我仍然会以另外的观点投入我的两分钱。
我知道这个问题是C#,但我认为对于像后缀运算符这样的东西它没有比C更不同的行为:
int main(){
int x = 0;
while (x<1)
x = x++;
}
编译器生成的程序集(是的,我编辑它使其更具可读性)显示
...
mov -8(rbp), 0 ; x = 0
L1:
cmp -8(rbp), 1 ; if x >= 1,
jge L2 ; leave the loop
mov eax, -8(rbp) ; t1 = x
mov ecx, eax ; t2 = t1
add ecx, 1 ; t2 = t2 + 1
mov -8(rbp), ecx ; x = t2 (so x = x + 1 !)
mov -8(rbp), eax ; x = t1 (kidding, it's the original value again)
jmp L1
L2:
...
等效地,循环正在做类似的事情:
t = x
x = x + 1
x = t
旁注:打开任何优化都可以得到一些像这样的汇编结果:
...
L1:
jmp L1
...
它甚至懒得存储你告诉它给x的值!
答案 10 :(得分:0)
尝试调用++ x并查看是否有效。
答案 11 :(得分:0)
将增量运算符放在变量之后意味着增量和赋值在 之后表达式被评估...所以 原声明 x = x ++; 翻译成 1.评估x并将值存储在tyransient内存中 ...现在执行由++运算符调用的代码....(步骤2和3) 2. x的增量值(在瞬态存储器中) 3.将增量值分配给x的存储位置 ......现在,继续执行该线的其余部分,在左边,有一个=符号...... 5.所以将步骤1中存储的值(未增加的值)赋值给= sign ...左边的表达式,即x
答案 12 :(得分:0)
也许我不对,但我更容易理解类似例子的结果:
public static void main(String[] args) {
int x = 10;
int y = 0;
y = x + x++; //1, 2, 3, 4
x += x; //5
System.out.println("x = " + x + "; y = " + y); //6
}
让我们一步一步看看y = x + x ++的操作:
现在让我们回到我们的示例并执行相同的步骤:
public static void main(String[] args) {
int x = 10;
x = x++; //1, 2, 3, 4
System.out.println(x); //5
}
答案 13 :(得分:-2)
作为独立语句,x++;
既是增量又是赋值。似乎对于什么时候发生的事情存在一些混淆。如果我们有
int x = 10;
int y = (x++) + 2;
我们将获得x = 11
和y = 12
。分配x的当前值,然后然后 x的增量和重新分配。 因此,当使用相同的变量时,
int x = 10; // Create a variable x, and assign an initial value of 10.
x = x++; // First, assign the current value of x to x. (x = x)
// Second, increment x by one. (x++ - first part)
// Third, assign the new value of x to x. (x++ - second part)
无论你怎么看,x的新值都是11。
我完全错了。
答案 14 :(得分:-3)
简单说明:
x ++是后缀增量。
编译器的作用:
a)将x的值赋给x b)增加x的临时值(我猜它甚至可以优化掉) c)丢弃临时值x
如果您希望代码在分配时返回11,请写:
x = ++ x;
答案 15 :(得分:-4)
作业的结果
x = x++;
在C和C ++ 中未定义,我也会猜测C#也是如此。
因此,发生的实际操作顺序取决于编译器如何决定实现它,不能保证分配或增量是否会首先发生。
(这在C#中有很好的定义,正如Jon Skeet在评论中指出的那样。虽然我现在觉得这个答案现在的价值低得多,但我保留这个帖子,因为OP的问题及其答案未被删除。评论。)
但是,在这种情况下,似乎发生的操作顺序是:
通过这种方式,虽然增量发生了,但它被旧值赋值所取代,因此将x保持为10.
HTH