【问题标题】:C#'s operators' order of operationC#的操作符的操作顺序
【发布时间】:2011-11-20 22:15:12
【问题描述】:

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

有人知道为什么要执行“begin++”吗?疯狂的是,如果我在 i=0 的情况下运行 (i % 2) == 0,即时窗口返回 true。

【问题讨论】:

  • 这甚至是在 C++ 中定义的行为吗?
  • 如果这不能说服你停止编写这样的代码,我不知道会怎样。
  • @SimpleCoder - 我认为我们在 C# 中看到了 2 个步骤
  • @CodeInChaos:不,这不是 C++ 中定义的行为,因为i++ 在序列点之间既递增又读取。
  • 你在 C++ 中得到“正确”的行为完全是偶然的; C++ 中没有“正确”的行为。或者,更确切地说,每个行为都是正确的。在 C# 中,只有 一个 正确的行为,我向你保证,你得到了它。如果您期望不同的行为,那是您的期望不正确,因此我的建议是开始期望 C# 中的正确行为,并停止依赖 C++ 中的实现细节。

标签: c# c++ operator-precedence


【解决方案1】:

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

在 C# 中,i++i % 2 之前评估,因为它位于左侧。因此i % 2 为假,if 的右侧被评估。

首先你使用优先级来获取语法树:

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

在每个节点上,您从左到右评估子节点。这意味着 i++i % 2 之前被评估。

Eric Lippert 在 SO 上和他的博客上都有很多关于此的帖子:

我个人会避免使用此类代码。将其拆分为多个表达式会更好,甚至可以使用普通的if 语句而不是? :


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

【讨论】:

  • 在此基础上,您可以将其更改为 buffer[i] = (i++ % 2) == 0 ? temp[end--] : temp[begin++];
  • @Rob: buffer[i] = i++ 由于缺少序列点,仍然是未定义的行为。
  • @FredOverflow:我认为他的意思是这样可以解决 C# 中的问题,尽管 C++ 中没有。
【解决方案2】:

我不知道,但你为什么不把你的意图说清楚?

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

i++;

【讨论】:

  • 我什至会把 i++ 放在if 之后。更高的运算符优先级意味着更早的执行是一个常见的神话。
  • 我想我会引入一个 temp 并避免两次写入 buffer[i++]。但是,是的,这是处理这个问题的正确方法。事实上,我在单独的行上写增量没有问题,这样做时没有参数。
【解决方案3】:

你确定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--];
}

我将循环条件改回&lt;,并添加了if,以防出现奇数个元素。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-02-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-26
    相关资源
    最近更新 更多