块返回值时调用的是什么?

时间:2011-12-01 15:45:26

标签: c++ c gcc terminology

我最近遇到过这个代码,这对我来说看起来不合法(但是gcc编译它)。我不介意构造,因为它想要一个名字:

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

显然,最后一个语句的值将作为由命名空间限定的表达式的“值”返回。

编辑:谢谢你的回答。事实证明,这是对称为Statement Expressions的普通C的扩展。

6 个答案:

答案 0 :(得分:12)

不是命名空间是宏,最多返回两个值。
语句末尾的\用于附加多个语句并创建多行宏。

代码不是标准C ++,但它在gcc中编译,因为它支持 gcc compiler extension

好读:

声明表达:
复合语句是由大括号括起来的一系列语句。在GNU C中,括号内的复合语句可能在所谓的Statement expression中显示为表达式。

         .--------------.
         V              |
>>-(--{----statement--;-+--}--)--------------------------------><

语句表达式的值是要在整个构造中出现的最后一个简单表达式的值。如果最后一个语句不是表达式,则构造的类型为void且没有值。

注意:此摘录摘自IBM XL C / C ++ v7.0文档。

答案 1 :(得分:7)

这称为语句表达式,是GCC的非标准extension。它允许您将复合语句用作表达式,其值由复合语句中的最后一个表达式给出。

这里使用它来避免类似函数的宏可能多次评估其参数的问题,如果这些评估具有副作用,则会产生意外行为。我们会仔细编写宏来评估ab一次。

在C ++中,你永远不需要做这样的事情 - 改为使用函数模板:

template <typename T> T max(T const & a, T const & b) {
    return a > b ? a : b;
}

答案 2 :(得分:2)

首先,它不是标准C ++,因为typeof是GCC对C ++的扩展。还有另一个扩展名,在代码中使用了Statement Extension。

使用-pedantic选项编译代码,它将无法编译。

至于问题,它不是命名空间。它只是一个宏,最多可以提供两个值。

答案 3 :(得分:2)

在这种情况下,{}运算符是一个“匿名范围运算符”(又名“词汇封闭”,“形式”和其他各种东西。它们被用来,有点类似于命名空间,以限制_a和_b的范围在大括号内,因此它们不会与您可能具有相同名称的其他变量发生冲突。{braces}中定义的“auto”变量将在达到右大括号后被“销毁”;或者,在非本地转移,如“返回”或“longjmp”。但是,你不能可靠地使用“转到”来提升它们。

你可能只习惯在“if”,“do”,“while”和“for”运算符之后看到它们,但是把它看作是将多个语句“捆绑”成一个“槽”的一种方式, “就像你将多个语句作为”if“的”then“或”else“子句运行一样(其中,省略了大括号,你只有一个语句”slot“)

正如Mike Seymour指出的那样,({})操作是一个非标准的GCC扩展,它返回在其中评估的最后一项的值。它与一般范围操作符非常相似,除了最后的固有返回。

答案 4 :(得分:1)

这是一个宏,就像任何其他#DEFINE一样。实质上,编译器将MAX(a,b)替换为其中定义的代码。这将返回最大值。

答案 5 :(得分:0)

这可能被认为是题外话,但是这个问题的标题出现在我的网络搜索中,同时正在寻找一种从{}块返回值的方法。然后我意识到了如何从标准c ++构造中做到这一点。我将此邮件发布给出于同样原因而在此登陆的下一个人。

要了解@BRPocock在这8年前所说的话,有可能从“匿名作用域运算符” /“词法包围物”中返回一个值,因此可以使用{}块作为表达式的一部分-通过使用 lambda函数

(历史除外:Lisp中的所有绑定形式都可以使用lambda表达式以宏的形式编写。Lisp是现代术语“ lambda函数”的来源。Lisp是John McCarthy在1959年提出的理论上的“ lambda”程序化体现微积分”)。

回到c ++,这是一个最小的匿名lambda函数,没有词法捕获,没有参数和一个空主体:

[](){}

这是不应用于任何参数的函数:

[](){}()

这里是函数调用,其中带有一些语句:

[](){ int i=2; int j=3; return i+j; }()

周围有一些多余的“东西”(可以用宏封装),它需要显式使用return,但它满足返回值的基本功能。来自{}块。例如,这将打印5:

std::cout << [](){ int i=2; int j=3; return i+j; }() << std::endl;