简单的混乱循环和可变工作

时间:2011-07-06 07:13:10

标签: javascript

在这个问题中,我问下面的代码片段是如何工作的,因为它涉及奇怪的变量使用:

while (+(+i--)!=0)
{
    i-=i++;
}
console.log(i);

5 个答案:

答案 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”或“代码混淆”的概念。这种方式使代码更难以读取和调试,因此可以防止对代码进行反向工程: - )