【问题标题】:Why exactly this will not compile if (a) b = c, d = e, return;?为什么如果 (a) b = c, d = e, return; 这将无法编译?
【发布时间】:2014-01-12 22:35:37
【问题描述】:

我沉迷于“无括号”ifs,像这样:

if (a) b++, c++, d = e; 

但有一件烦人的事情是return 不能成为最后一部分的一部分。直觉上我觉得为什么会这样,但是任何人都可以用编程语言来解释为什么这不会编译吗?

main() {
    int a, b, c, d, e;
    if (a) b = c, d = e, return;
}

如果你在乎,也请解释一下为什么会这样设计,这对我来说似乎是一个缺陷。我可以在 C 中理解,但在 C++ 中,它可以重新设计,而不会与现有 C 代码发生重大兼容性损失。

只是为了比较:这些将编译并完全符合预期:

while (a < 10) a++, b--, c += 2;

while (a < 10) if (a == 5) half = a, save();

【问题讨论】:

  • 你在圣诞老人的淘气名单上。
  • return b = c, d = e; 不会让你的船浮起来?它不会浮动我的,但那些用于无括号 if 的逗号也不会。
  • 这简直是邪恶的——如果你写这样的代码,我不会雇用你。
  • 因为设计者认为if (a) [&amp;]{ b = c, d = e; return; }(); 提供了足够的功能(警告:仔细阅读:))。或者你可以写if (a) return b = c, d = e, void();
  • @DeadMG 我认为很明显我说的是实际的符号括号{},而不是一些隐喻的概念。

标签: c++ compiler-errors operators


【解决方案1】:

“逗号”运算符就是这样,一个运算符。左右两边必须是表达式,return不是表达式。

更详细地说,逗号运算符首先评估其左侧,然后丢弃该值。然后,它计算右侧的值,整个逗号表达式计算为右侧的值。

类似这样:

template <typename T, typename U>
U operator,(T t, U u)
{
    return u;
}

因此,您不能在逗号表达式中放入不是表达式本身的任何内容。

如果您希望同时执行一系列语句并将它们组合在一起,这正是;{} 的用途。没有理由在逗号运算符中重复该行为。

【讨论】:

  • @DeadMG:这很好地回答了“为什么”语句不能编译,这是主要问题。
  • @exebook 我相信分号; 很好地填补了这个角色。分号分隔表达式,大括号{} 连接它们。
  • 说“语句无法编译,因为语言是这样设计的”并不能真正解释为什么语言是这样设计的。
  • @DeadMG:首先,没有人这么说。其次,“为什么语言是这样设计的”是次要问题。主要问题是为什么它不会编译。这个问题回答了这个问题,它没有说任何与“该语句无法编译,因为语言是这样设计的”相当的内容。
  • @DeadMG 在阅读了您对问题的回答后,我不确定您要在这里说什么。我的回答可能是,“因为语言不是这样设计的”,但你的回答是,“因为没有人希望语言被这样设计。”我看不出我们的答案有什么真正的区别。
【解决方案2】:

可以通过以下方式完成

if (a) return ( b = c, d = e, 0 );

如果没有返回表达式则为oe

if (a) return ( b = c, d = e, ( void )0 );

【讨论】:

    【解决方案3】:

    这是否回答了 OP 真正提出的问题可能会有疑问,但如果有人关心为什么逗号运算符的设计方式如此,我认为它可以追溯到 BCPL。

    在 BCPL 中,您可以组合一系列作业,例如:

    L1 := R1
    L2 := R2
    

    ...变成单个语句(命令),例如:

    L1, L2 := R1, R2
    

    很像在 C 和 C++ 中,这些是按从左到右的顺序执行的。与 C 和 C++ 不同,这个“逗号运算符”不会产生单个表达式(至少 C 使用该术语)。

    BCPL 还有一个resultis,可以让你将一个语句块变成几乎像一个函数的东西。

    至少在我看来,在 C 语言中,Dennis1 决定将这两个概念组合成一个更简单的概念:一个逗号运算符,它允许对连续的多个表达式,并产生一个结果。

    参考:BCPL Reference Manual


    1. 我想公平地说,我应该提到这个决定实际上是由 Ken Thomson 在 B 的设计中做出的。幸存下来的关于 B 的文档很少,几乎不可能猜测到这一点。

    【讨论】:

      【解决方案4】:

      如前所述,return 不是表达式,而是关键字。然而,b = c, d = e 一个表达式。因此,您的意图可能是这样的:

      if (a) return (b = c, d = e, 0);
      

      b = c, d = e, return 没有任何意义,因为它与逗号运算符在其他上下文中的工作方式不一致。想象一下,如果你能做到这一点:

      for (int i = 0, j = 0, return; ...
      

      那绝对没有意义。如果return 在这种情况下意味着某些东西,那也是多余的,因为逗号运算符已经返回了它的最后一个操作数。也没有意义,因为逗号运算符已经计算了它的操作数,return something 在这种情况下会有什么好处?

      查看您的代码的人可能会浏览它并说:“这应该是:if (a) (b = c, d = e); return 0;”,这是一个陷阱,因为缺少大括号。他们真正的意思是if (a) { (b = c, d = e); return 0; },但是如果您使用此答案顶部提到的语法,则可以避免此问题。它根本不可读,因为它没有语义意义。

      无论如何,这只有在bd 是全局变量时才有意义,例如errno,允许您分配给变量并在一个语句中返回。

      【讨论】:

        【解决方案5】:

        为什么如果 (a) b = c, d = e, return; 这将无法编译?

        这是因为逗号 (,) 运算符的左右操作数必须是表达式return 语句不是表达式。请参阅 C 和 C++ 标准为 , 运算符定义的语法:

        C11:6.5.17 逗号运算符

        Syntax
              expression:
                     assignment-expression
                     expression , assignment-expression
        

        相同的语法由 C++ 标准定义

        C++:5.18 逗号运算符 [expr.comma]

        逗号运算符从左到右分组。

              expression:
                     assignment-expression
                     expression , assignment-expression  
        

        一对以逗号分隔的表达式1从左到右计算;

        请注意,标准中提到了表达式,而return 不是表达式。


        1.重点是我的

        【讨论】:

        • 我再次要求反对者发表评论。
        • 我投了反对票,因为问题是关于 C++ 的,而且你引用了 C 标准。
        • @DeadMG;那么为什么这个问题用 C++ 标记呢?询问 OP。
        • @DeadMG:虽然节号更改为 5.18,但 C++ 标准给出了相同的语法。
        • 我承认,我的评论有误。问题问“为什么?”。标准说“什么”。这对两个标准同样适用。
        【解决方案6】:

        我可以在 C 中理解,但在 C++ 中,它可以在没有的情况下重新设计 与现有 C 代码的主要兼容性损失。

        可能是,但为什么会有人想要它呢?该语言已经包含了您正在寻找的最终方法 - 大括号。它们比像您一样滥用逗号运算符更可靠和有用。例如,如果您正在使用 UDT,那么当我重载逗号运算符时,您会遇到一些令人讨厌的意外。糟糕!

        更重要的是,将return 作为表达式没有意义,因为该函数在计算时已经返回,所以任何人都不可能使用任何假设的返回值。

        您的整个问题都是基于您个人对牙套的厌恶程度。没有其他设计该语言的人真正拥有这种感觉。

        【讨论】:

          猜你喜欢
          • 2012-01-27
          • 1970-01-01
          • 2015-08-02
          • 1970-01-01
          • 1970-01-01
          • 2016-05-02
          • 1970-01-01
          • 2018-03-28
          • 2017-07-28
          相关资源
          最近更新 更多