我在我开始研究的项目中遇到了这段代码。最初的开发人员已经不再可用了,我无法理解它:
k = (j = (i = 0) + 2) + 1;
return i|= j|= k|= (j+= i) - - (k+++k) - - (i =+j);
它产生的值为11
。这是如何工作的?
什么是=+
运营商?
什么是+++
运营商?
什么是- -
运营商?
什么是|=
运营商?
答案 0 :(得分:191)
什么是
=+
运营商?
这是两个运算符,一个赋值运算符=
和一个一元加号+
,它什么都不做。
您是否拼错了并且指的是复合赋值运算符+=
?
什么是
+++
运营商?
还有两个运算符,一个后增量,++
和一个加法+
,(根据最大蒙克规则,选择最长的有效令牌,它将成为一个加法和两个一元加上如果选择了最短的有效令牌。)
什么是
- -
运营商?
再两个算子,一个减法和一个一元减(否定)。
什么是
|=
运营商?
复合赋值,按位[或者,在boolean
值的情况下,逻辑运算]左侧值与右侧值并将其存储在左侧 - 手边变量。
a |= b;
几乎相当于
a = a | b;
但是左侧操作数只被评估一次,而后者可能需要一个显式的强制转换,而前者则不需要。
k = (j = (i = 0) + 2) + 1;
return i|= j|= k|= (j+= i) - - (k+++k) - - (i =+j);
它产生的值为11.这是如何工作的?
第一行相当于
i = 0;
j = i+2;
k = j+1;
赋值(例如i = 0
)求值为存储的值(此处为i
)。
下一行是适当的间距,并添加了隐含的括号
return i |= (j |= (k |= (((j += i) - (-(k++ + k))) - (-(i = +j)))));
i |= stuff_1
:i
被评估(0),stuff_1
被评估,按位或被采用,结果存储在i
中。由于i
最初为0,因此相当于i = stuff_1
。
j |= stuff_2
:j
被评估(2),stuff_2
被评估,按位或被采用,结果存储在j
。< / p>
k |= stuff_3
:k
从左到右进行评估(3),然后stuff_3
。
(j += i)
将i
添加到j
,将总和存储在j
中,并返回j
的新值。
由于i
为0,j
不会更改,值为2。(k++ + k)
获取旧值k
(3),增加k
并添加k
的新值(4),结果为7.该值为否定,从2中减去否定值(-7),得到2 - (-7) = 9
。 (i = +j)
将j
(2)的值存储在i
中,表达式的值也是2.该值被否定(-2)并从中减去我们从前面的操作得到的9,所以stuff_3
评估为11,副作用是
i
的存储值现在为2 j
的存储值现在为2(实际上没有变化,因为i
最初为0)k
的存储值现在为4 k
(3)的旧值按位或按11,结果为11,存储在k
中,11为stuff_2
的值,是k |= stuff_3
。 j
(2)的旧值与stuff_2
(11)的值按位或按位,结果为11.该值存储在j
中,stuff_1
(j |= stuff_2
)的值为11。
i
(0)的旧值与stuff_1
(11)的值按位或取值,结果存入i
,且值为i |= stuff_1
为11.然后返回该值。
答案 1 :(得分:42)
原始开发者已不再可用,我无法理解。
原始开发者故意在代码中留下了一个曲折的任务问题。 这与Daniel Fischer给出的答案完全相同,但为了清楚地解释,我将按照与评估顺序相对应的步骤进行评估。
k =(j =(i = 0)+ 2)+ 1;
括号&amp;运算符优先级,评估为:
i = 0;
j = i + 2; // j = 2
k = j + 1; // k = 3
返回i | = j | = k | =(j + = i) - - (k +++ k) - - (i = + j);
扩展&#34; | =&#34;运营商,这相当于:
return i = i | ( j = j | ( k = k | ( (j+= i) - - (k+++k) - - (i =+j) ) ) );
左边&#34; |&#34;始终首先评估运算符并记住,因此将变量值替换为左侧:
return i = 0 | ( j = 2 | ( k = 3 | ( (j+= i) - - (k+++k) - - (i =+j) ) ) );
然后评估每个&#34; |&#34;的右侧;运算符(带括号,运算符和从左到右的优先级):
(j+= i): pre-increments j = j + i; // j = 2 + 0 = 2
then expression evaluates to j // evaluates to 2
(k+++k): first evaluates k++ // sub-expression evaluates to 3,
// then post-increments k: k = 4
then evaluates (k++)+k // evaluates to 3+4 = 7
(i =+ j): "=+" is not an java operator!!
it is evaluated as "=" operator followed by unary "+" operator
expression evaluates to +j // evaluates to 2
k = 3 | ( (j+= i) - - (k+++k) - - (i =+j) )
= 3 | ( 2 - -7 - -2) = 3 | 11 = (2+1) | (8+2+1) = (8+2+1) = 11
j = 2 | k
= 2 | 11 = (2) | (8+2+1) = 8+2+1 = 11
i = 1 | j;
= 1 | 11 = (1) | (8+2+1) = 8+2+1 = 11
return i; // return 11
答案 2 :(得分:18)
对我来说,最好的答案是Mike Rylander(评论中)。
将其替换为
return 11;
并提交。
我的意思是,代码不依赖于之前编写的任何内容,因此每次生成11。这是一个复杂的计算,花费时间什么都没有并产生11.所以你只需要返回11.不要保留开发者的无用代码,他们显然对你很开心。它让我想起了一位前同事,他在代码中设置了一个炸弹(很少崩溃,但有时甚至崩溃),就在辞职之前......
注意:可能存在不等效的情况:如果i,j和k在您的方法之外可见,并在其他地方重复使用。但这不太可能。
答案 3 :(得分:16)
您的程序在C中调用未定义的行为。您正在两个序列点之间多次修改i
和j
。
在Java和JavaScript中,行为定义明确,您必须查看运算符的优先级和关联性。