在这个问题中,我问下面的代码片段是如何工作的,因为它涉及奇怪的变量使用:
while (+(+i--)!=0)
{
i-=i++;
}
console.log(i);
答案 0 :(得分:5)
有趣的问题...你已经将它标记为Java,JavaScript和C - 请注意,虽然这些语言具有相同的语法,但这个问题涉及非常微妙的语义,可能(我不确定)语言不同。< / p>
让我们分解一下:
+(+i--)
--
postfix减量运算符最紧密绑定。所以这相当于+(+(i--))
。因此,这相当于+(+i)
的值(即i
),但在获取值后它也会递减i
。它将值与0进行比较,以查看循环是否应该继续。因此,while (+(+i--)!=0)
等同于以下内容:
while (i-- != 0)
请注意,它也会在循环结束时执行i--
。
在循环中,我相信你有一些未定义的行为,至少在C中,因为你在右边引用i
,并且在左边更新i
- 我相信C没有定义执行该操作的顺序。因此,您的结果可能因编译器而异。至少Java是一致的,所以我会给出Java答案。 i-=i++
相当于i = i - i++
,相当于读取表达式中的所有值,计算表达式的结果应用后增量,然后分配结果。那就是:
int t = i - i; // Calculate the result of the expression "i - i++"
i++; // Post-increment i
i = t; // Store the result back
显然,这与撰写i = 0
相同。所以循环体将i设置为0。
因此,循环只执行一次,将i设置为0.然后,它在下一个while循环中再次递减i
,但由于i
(在递减之前)= {}失败了= 0。
因此,无论-1
的初始值是什么,最终答案都是i
。
将这些全部放在一起并编写一个等效的程序:
while (i-- != 0)
{
int t = i - i;
i++;
i = t;
}
console.log(i);
当我在Java和JavaScript中尝试时,这就是我得到的。对于GCC(C编译器),它仅在i
从0开始时给出-1。如果i
以其他任何东西开始,它将进入无限循环。
那是因为在GCC(不一定是所有C编译器)中,i-=i++
具有不同的含义:它首先将商店返回i
,然后然后执行后增量。因此,它等同于:
int t = i - i; // Calculate the result of the expression "i - i++"
i = t; // Store the result back
i++; // Post-increment i
这相当于写i = 1
。因此,在第一次迭代时,它将i
设置为1,然后在循环上检查i == 0
是否为i
,它是否再次出现,始终设置{{1}这将永远不会终止,但对于i
从0开始的特殊情况;那么它总是会终止循环并递减i
(所以你得到-1
)。
另一个C编译器可能会选择像Java一样行事。这表明你应该从不编写分配和后增加相同变量的代码:你永远不知道会发生什么!
编辑:我试图使用for
循环过于聪明;这不等同。转回了一个循环。
答案 1 :(得分:1)
那真是太棒了! (我喜欢它)
首先,您可以忘记+(+
... )
部分,就像说1 + (+1) = 2
一样。
i--
表示i = i - 1
。在while
条件下,您可以测试i--
是否与0
不同。注意:测试是在i != 0
上进行的,然后i
的值已更改。如果您想在>>测试之前更改其值,则应该使用--i
代替。
关于i -= i++
,说i = 0
是一种非常愚蠢的方式。您必须从右到左阅读:i = i + 1
然后i = i - i
1 (无论您拥有i
的任何值,您最终都会得到{{1} }}
Simplier quivalent snippet:
0
1 while (i-- != 0) {
i = 0;
}
console.log(i);
表示a -= b
。
答案 2 :(得分:0)
i -= i++
与i = i-i; i++
的含义相似(如果您明确-=
)。
以类似的方式,您可以将i--
的副作用拉出循环条件
将while (foo(i--)) { ... }
转换为while (foo(i)) { i--; ...} i--;
(你需要将它放在循环体中和循环之后,因为最后,条件将为false并且循环体不会被执行但是执行后继续while循环)。
答案 3 :(得分:0)
while条件评估基于运算符优先级进行。我使用显式括号来帮助理解评估:
(+(+(i - ))!= 0)相当于使用(i--!= 0)作为'+'只是一元运算符。
表达式i - = i ++;相当于i = i - i ++;其中LHS表达式从左到右进行评估。
i = 4;
while (+(+i--)!=0) //here i would be decremented once to 3.
{
i-=i++; // here i = 3 - 3 = 0; even though i has been incremented by 1 its value is set to 0 with this assignment
}
答案 4 :(得分:0)
这很简单。我认为像这样编码的唯一理由是一个名为“代码obfucasion”或“代码混淆”的概念。这种方式使代码更难以读取和调试,因此可以防止对代码进行反向工程: - )