2011-11-20 128 views
0

我正在将C++实用程序移植到C#。当我用C++运行下面的语句时,我得到了正确的操作。当我在C#中运行相同的语句,但是......C#的操作员的操作顺序

omgwtfbbq

有谁知道为什么“开头++”执行?疯狂的事情是,如果我运行(i%2)== 0与i = 0,立即窗口返回true。

+4

这是甚至在C++中定义的行为? – CodesInChaos

+0

哪个是哪个? –

+8

如果这不能说服你停止编写这样的代码,我不知道会发生什么。 –

回答

12

运算符优先级在这个问题中是无关紧要的。这是导致此行为的评估顺序。

在C#i++之前评估i % 2,因为它在左侧。因此i % 2是错误的,并且if的右侧被评估。

首先使用优先得到语法树:

= 
    buffer[i++] 
    if i % 2 
    then temp[end--] 
    else temp[begin++] 

在从左至右你评估孩子的每个节点。这意味着i++i % 2之前被评估。

埃里克利珀有大量的对这个职位的,都在这里对SO,并在自己的博客:

个人而言,我会避免这样的代码。这是好得多把它分割成多个表情,甚至使用普通的if声明,而不是? :


在C++中访问这是两者之间是不确定的行为写入没有序列点的变量。我认为=不是序列点,所以我猜你的表达式在C++中是未定义的,只是碰巧工作。

+1

在此基础上,你可以改变它为'buffer [i] =(i ++%2)== 0? temp [end--]:temp [begin ++];' – Rob

+3

@Rob虽然这会工作,但它仍然是可怕的代码。 – CodesInChaos

+0

啊我看到了,谢谢你的解释(和链接)。 – tlg

3

我不知道,但你为什么不直接明确你的意图?

if(i % 2 == 0) { 
    buffer[i] = temp[end--]; 
} else { 
    buffer[i] = temp[begin++]; 
} 

i++; 
+0

我甚至会在if后加上i ++。而较高的运算符优先级意味着较早的执行是一个常见的神话。 – CodesInChaos

+0

我想我会介绍一个温度,并避免两次写入缓冲[i ++]。但是,是的,这是处理这个问题的正确方法。事实上,我没有问题在单独的行上写增量,当这样做时没有参数。 –

+0

@CodeInChaos:你说得对,编辑过。 – Ryan

0

你确定begin < end是正确的?如果我没有弄错,你会错过最后一个元素。

这是我会怎么写C++:

for (; begin <= end; ++i) 
{ 
    buffer[i] = temp[(i & 1) == 0 ? end-- : begin++]; 
} 

但是,如果你仔细想想,在循环内的条件真的是没有必要的,因为它的触发器与每一个迭代。这将是更有效的方法简单地有两个复制操作的循环中:

while (begin < end) 
{ 
    buffer[i++] = temp[end--]; 
    buffer[i++] = temp[begin++]; 
} 
if (begin == end) 
{ 
    buffer[i++] = temp[end--]; 
} 

我改变循环条件回<和的情况下添加一个if有奇数个元素。