【问题标题】:C++ Perincrement Undefined Operation vs CC++ 增量未定义操作 vs C
【发布时间】:2014-12-26 22:49:32
【问题描述】:

我有这行代码:

front = (++front) % size;

在 C 中我没有收到警告,但在 C++ 中我收到警告 operation on front may be undefined [-Wsequence-point]。这种预增量使用如何导致未定义的行为?在我看来,这一行非常明确,会被解释为:

  1. 增加前端
  2. mod 前面有大小
  3. 为前面分配新值。

我的编译器只是抛出一个全面的警告吗?

附:如果我正在做类似front = front++; 或天堂禁止front = front++ + front++; 之类的事情,我理解警告。

编辑:此警告是使用 GCC (tdm-1) 4.6.1 在 Windows 64 上的 CodeBlocks 中产生的

【问题讨论】:

  • front++ vs ++front 在这里没有任何改变,等号的左边可能是后或前递增的值,具体取决于首先评估哪一侧。 AFAIK 没有义务在右侧之前评估 = 的左侧。
  • 我认为 thndrwrks 的问题在于这样的想法,即在 % 之后才能进行分配,而 % 直到 (++front) 之后才能发生分配,按顺序括在括号中给予++ 优先级,因此表面上看没有排序问题。虽然显然不是这样。我目前对规范还不够精通,无法给出明确的答案,但也许有人可以谈谈?
  • 伴侣。发帖前先搜索。
  • 我理解并查看了那个特定的帖子,但我仍然不清楚为什么这会在 C++ 中产生警告,但在 C 中不会产生警告。编辑:事实上,答案甚至声明“5) i = ++i + 1 ; //well defined behaviour”这类似于我的代码行。那么为什么我会收到警告呢?
  • 你为什么要这样做呢?为什么要修改i 两次?只需front = (front + 1) % size;。

标签: c++


【解决方案1】:

旧的排序规则有一些边缘情况,其中操作顺序已明确定义,但在技术上仍是未定义的行为。在 C++11 和 C11 中,已通过将序列点要求替换为“sequenced-before”和“sequenced-after”关系来解决此问题。

你的例子恰好是这样的情况。如果您在 C11 或 C++11 模式下收到警告,那么警告还没有针对新规则进行更新。在早期的 C 和 C++ 模式中,警告是正确的。如果您在早期模式中没有收到警告,那么它们根本没有实现,这没关系,因为“不需要诊断”。


同时,这行可以写得更清楚,在旧规则下也是正确的:

front = (front + 1) % size;

【讨论】:

    【解决方案2】:

    在 C++11 中这是明确定义的;结构同:

    i = ++i + 1;
    

    作为标准本身中定义明确的行为的示例给出。更详细的解释见AndreyT's answer here。

    在 C++03、C89 和 C99 中,这是未定义的行为,因为它们对 ++i 的排序规则更宽松。

    【讨论】:

    • 我不认为这完全是黑白的,因为标准没有明确说明何时发生左值到右值的转换,所以我认为围绕这​​种表达的讨论将在可预见的情况下继续进行未来:)
    • 我打赌他们会在 C++11 中解决这个问题。仅仅通过切换编译模式来明确定义您的程序 - 这是非常危险的游戏。
    • @Slava 我们在谈论 C++11(并且 AFAIK 它在 C++14 中没有改变)。切换到旧标准时让 C++11 程序中断是“可以的”,但这是我们应该避免的另一种方式
    • @MatMcNabb 如果程序无法以旧标准编译,那将是“OK”,在这种情况下,它会产生难以捕捉错误行为。这绝对不是“OK”。
    • @Slava:为了标准化线程,必须更精确地指定排序规则。并且所有标准修订都减少了未定义的行为(当然,反过来会很糟糕,并且应该只存在于真正需要的地方)。
    【解决方案3】:

    您在序列点之间更改了两次前面:一次通过 ++,一次通过赋值。 这是未定义的行为。

    【讨论】:

      【解决方案4】:

      将增加的值写回front 可以随时发生(在赋值修改front 之前或之后),因此警告有效且代码不安全。

      【讨论】:

      • 这种行为在 C 中与在 C++ 中是否不同?
      • 据我所知不是这样,但我对 C 的了解已经过时了。
      • 这很有趣 - 我怀疑传统上,代码总是先在右侧评估,然后在分配到左侧之前完成增量。但是,也许不是……这难道不是只有编译器优化才能影响的东西吗? (即没有优化,生成的代码不是得到严格的排序吗?)
      猜你喜欢
      • 2011-04-11
      • 1970-01-01
      • 2017-08-31
      • 2014-07-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-28
      • 1970-01-01
      相关资源
      最近更新 更多