【问题标题】:In what versions of C is a block inside parenthesis used to return a value valid?在哪些版本的 C 中,括号内的块用于返回有效值?
【发布时间】:2020-02-01 17:55:22
【问题描述】:

如果我这样做:

int j = ({int x = 7; x+3;});

在 i686-apple-darwin10-gcc-4.2.1 (GCC) 4.2.1 (Apple Inc. build 5646) gcc 中它编译得很好。有问题的块({int x = 7; x+3;}) 返回最后一条语句的值作为块的值。如果您删除括号它不会编译。我可以期望这在大多数 C 编译器中都能工作吗?

另外,这个构造的名称是什么?我在搜索它时遇到了很多麻烦,因为搜索引擎不索引 (){} 并且 C 是一个糟糕的搜索词。我也无法在我的任何书中找到任何关于它的内容,可能是因为我不知道该寻找什么。

【问题讨论】:

  • 请不要指望它能够工作,也不要指望人们能够阅读您的代码。

标签: c


【解决方案1】:

您可以期望它在大多数版本的 GCC 中工作。

您可以期望它几乎无法在其他任何地方工作 - 它是一个 GCC 扩展。

GCC 手册中描述该功能的部分标题为“表达式中的语句和声明”:

括在括号中的复合语句在 GNU C 中可能显示为表达式。

后来它说:

在语句表达式中的语句中创建的任何临时对象都将被销毁 在声明的结尾。这使得宏内部的语句表达式略微 不同于函数调用。

因此,“语句表达式”似乎是文档中使用的名称。

【讨论】:

  • clang 似乎也支持这一点。
  • Clang 支持 GCC 支持的大多数内容,以与 GCC 兼容。使用它不一定是个好主意。你必须选择它是否明智。
  • 只是陈述事实。 Clang 不是“几乎无处”恕我直言。对于使用它是否是一个好主意,没有主观评论。
  • Clang 在这个问题上“只是伪装的 GCC”——尽管内部结构完全不同。如果不是 GCC 支持它,我不确定 Clang 会不会,尽管这充其量只是一个半知情的推测性猜测,并且由于它受到支持,因此无法验证任何一种方式。 AFAIAC,它仍然是 GCC 扩展。是否决定使用它取决于您。我已经编写了 30 年没有语句表达式的代码,并且没有特别计划在接下来的 30 年中使用它,但会在必要时考虑什么是合适的。
【解决方案2】:

如果您删除括号,它不会编译。

如果没有括号,编译器会将其视为聚合初始化块,并在看到int 关键字时会失败。初始化块中不能有关键字。

6.7.8 初始化

11 标量的初始值设定项应为单个表达式,可选择用大括号括起来。这 对象的初始值是表达式的初始值(转换后);同类型 适用于简单赋值的约束和转换,采用标量的类型 成为其声明类型的非限定版本。

6.2.5 类型

21 算术类型和指针类型统称为标量类型。数组和 结构类型统称为聚合类型。


我可以期望这在大多数 c 编译器中都能工作吗?

没有。看起来像一个非标准的 GNU 扩展。

另外,这个构造的名称是什么?

不知道有没有。实际上,这类似于宏通常所做的事情。

【讨论】:

    【解决方案3】:

    这是一个GCC extension

    括在括号中的复合语句在 GNU C 中可能显示为表达式。这允许您在表达式中使用循环、开关和局部变量。

    回想一下,复合语句是由大括号括起来的语句序列;在这个结构中,括号围绕着大括号。例如:

     ({ int y = foo (); int z;
        if (y > 0) z = y;
        else z = - y;
        z; })
    

    foo () 绝对值的有效表达式(尽管比必要的稍微复杂一点)。

    复合语句中的最后一件事应该是一个表达式,后跟一个分号;此子表达式的值用作整个构造的值。 (如果您在大括号中最后使用某种其他类型的语句,则该构造的类型为 void,因此实际上没有任何值。)...

    【讨论】:

      猜你喜欢
      • 2010-09-14
      • 1970-01-01
      • 2013-05-18
      • 1970-01-01
      • 2015-12-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多