What is it called when a block returns a value?

2020-02-11 03:39发布

I came across this code recently, which doesn't look legal to me (but gcc compiles it). I don't so much mind the construction as want a name for it:

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

Apparently, the last statement's value is being returned as the "value" of the expression bounded by the namespace.

Edit: Thanks for the answers guys. Turns out this is an extension to plain C called Statement Expressions.

6条回答
等我变得足够好
2楼-- · 2020-02-11 03:46

This is called a statement expression, and is a non-standard extension of GCC. It allows you to use a compound statement as an expression, with a value given by the last expression in the compound statement.

It's used here to avoid the problem that function-like macros may evaluate their arguments multiple times, giving unexpected behaviour if those evaluations have side-effects. The macro is carefully written to evaluate a and b exactly once.

In C++, you should never need to do anything like this - use function templates instead:

template <typename T> T max(T const & a, T const & b) {
    return a > b ? a : b;
}
查看更多
不美不萌又怎样
3楼-- · 2020-02-11 03:55

This a macro, just like any other #DEFINE. Essentially, the compiler replaces MAX(a,b) with the code defined therein. This will return the max value.

查看更多
贪生不怕死
4楼-- · 2020-02-11 03:56

It is not a namespace, it is a macro which returns maximum of two values.
\ at the end of the statements is use to append multiple statements and create a multi-line macro.

The code is not standard C++ but it compiles in gcc because it is supported as an gcc compiler extension.

Good Read:

Statement Expressions:
A compound statement is a sequence of statements enclosed by braces. In GNU C, a compound statement inside parentheses may appear as an expression in what is called a Statement expression.

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

The value of a statement expression is the value of the last simple expression to appear in the entire construct. If the last statement is not an expression, then the construct is of type void and has no value.

Note: This excerpt is taken from IBM XL C/C++ v7.0 documentation.

查看更多
Anthone
5楼-- · 2020-02-11 03:59

First of all, it is not Standard C++, because typeof is an extension to C++, by GCC. There is another extension, called Statement Extension is used in the code.

Compile your code with -pedantic option, it will not compile.

As for the question, it is not namespace. It is just a macro, which gives you maximum of two values.

查看更多
闹够了就滚
6楼-- · 2020-02-11 04:04

The {} operators, in this context, are an "anonymous scope operator" (aka "lexical enclosure," "form," and various other things. They're being used, somewhat akin to a namespace, to limit the scope of _a and _b to within the braces, so they won't conflict with other vars you might have with the same names. "auto" vars defined within the {braces} will be "destroyed" after the closing brace is reached; or, on a non-local transfer, like a "return" or "longjmp". You can't, however, reliably use "goto" to broach them.

You're probably only used to seeing them after "if," "do," "while," and "for" operators, but think of it as a way to generally "bundle" multiple statements into one "slot," just as you would to run multiple statements as the "then" or "else" clause of an "if" (where, leaving out the braces, you have only one statement "slot")

As Mike Seymour pointed out, the ({}) operation is a non-standard GCC extension, which returns the value of the last item evaluated within it. It's very similar to the general scoping operator, except the inherent return at the end.

查看更多
可以哭但决不认输i
7楼-- · 2020-02-11 04:04

This may be seen as off topic, but the title of this question came up in my web search while looking for a way to return a value from a {} block. Then I realized how to do it from standard c++ constructs. I post this for the next person who lands here for the same reason.

To pick up on what @BRPocock said, lo these 8 years ago, it is possible to return a value from a “anonymous scope operator” / “lexical enclosure” — hence use a {} block as part of an expression — through the use of lambda functions.

(Historical aside: all of the binding forms in Lisp can be written in terms of macros using lambda expressions. Lisp is where the modern term “lambda function” comes from. Lisp was John McCarthy's 1959 procedural embodiment of the theoretical “lambda calculus” of Church and Turning.)

Back to c++, this is a minimal anonymous lambda function, with no lexical capture, no arguments, and an empty body:

[](){}

This is that function applied to no arguments:

[](){}()

Here is that function call with some statements in its body:

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

There is some extra “stuff” around it (which could be encapsulated with a macro) and it requires explicit use of return, but it meets the basic functionality of returning a value from a {} block. For example this will print 5:

std::cout << [](){ int i=2; int j=3; return i+j; }() << std::endl;
查看更多
登录 后发表回答