44

浏览 Linux 内核源代码,我发现了一段代码,其中用括号括起来的语句块被视为表达式a la lisp(或 ML),即值为最后一条语句的值的表达式。

例如:

int a = ({
    int i;
    int t = 1;
    for (i = 2; i<5; i++) {
        t*=i;
    }
    t;
});

我一直在研究ANSI C 语法,试图弄清楚这段代码如何适合解析树,但我没有成功。

那么,有人知道这种行为是标准规定的还是只是 GCC 的特性?

更新:我已经尝试使用标志 -pedantic 并且编译器现在给了我一个警告:

warning: ISO C forbids braced-groups within expressions
4

2 回答 2

42

这不是标准 C。它是一个 gcc 扩展,称为语句表达式您可以在此处找到 C 扩展的完整列表。这实际上是Linux 内核中使用的众多 gcc 扩展之一,并且似乎clang 也支持这一点,尽管它没有在文档中明确命名。

正如您观察到的最后一个表达式用作表达式的值,文档说(强调我的):

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

主要好处之一是制作安全的宏,以避免对具有副作用的参数进行多次评估。给出的示例使用了这个不安全的宏:

#define max(a,b) ((a) > (b) ? (a) : (b))

它计算一次ab两次,并且可以使用如下语句表达式重写以消除此问题:

#define maxint(a,b) \
   ({int _a = (a), _b = (b); _a > _b ? _a : _b; }) 

注意,需要显式使用intwhich 可以使用另一个gcc扩展Typeof来修复:

#define max(a,b) \
   ({ typeof (a) _a = (a), _b = (b); _a > _b ? _a : _b; }) 

请注意,clang 还支持 typeof

于 2013-09-19T03:11:26.613 回答
38

它被称为“表达式中的支撑组”。

ANSI/ISO C 和 C++ 都不允许,但 gcc 支持它。

于 2009-08-06T10:15:33.180 回答