Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does `({...})` return a value?

Tags:

c

gcc

I recently found this GCC macro:

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

I didn't realize before I saw this code, that a block of code {...} can somehow return value in C.
1) Could you give me a hint how this works?

Though, I usually was able to achieve the same result by abusing the comma operator:

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

or if it was only for side-effect I would use do { ... } while(0)

2) What is the preferred way of doing this?

like image 663
Vladimir Keleshev Avatar asked Oct 19 '11 20:10

Vladimir Keleshev


People also ask

How does a function return a value?

A return is a value that a function returns to the calling script or function when it completes its task. A return value can be any one of the four variable types: handle, integer, object, or string. The type of value your function returns depends largely on the task it performs.

How does a JavaScript function return a value?

JavaScript passes a value from a function back to the code that called it by using the return statement. The value to be returned is specified in the return. That value can be a constant value, a variable, or a calculation where the result of the calculation is returned.

How does a Python function return a value?

A Python function will always have a return value. There is no notion of procedure or routine in Python. So, if you don't explicitly use a return value in a return statement, or if you totally omit the return statement, then Python will implicitly return a default value for you.

How can you retrieve a value from a method?

Within the body of the method, you use the return statement to return the value. Any method declared void doesn't return a value. It does not need to contain a return statement, but it may do so.


2 Answers

It is a GCC extension. The comma operator doesn't work:

// C89, doesn't work...
#define max(a,b) \
    (typeof (a) _a = (a), \
     typeof (b) _b = (b), \
     (_a > _b ? _a : _b)) 

The comma operator only works with expressions, and typeof(a) _a = (a); is a declaration, not an expression. It is not really possible to write an equivalent macro without either GCC extensions or C11, which has _Generic. Note that typeof is als a GCC extension, so you don't gain any portability by eliminating ({...}) unless you eliminate typeof too.

Here is a C11 version, note how verbose it is by comparison (and it only handles two types!). C11 isn't even supported yet, good luck trying to find a compiler to test this:

// C11
static inline int maxi(int x, int y) { return x > y ? x : y; }
static inline long maxl(long x, long y) { return x > y ? x : y; }
#define max(x, y) _Generic((x), \
    long: maxl(x,y), \
    int:_Generic((y), \
        int: maxi(x,y), \
        long: maxl(x,y)))

In portable C99, you can write a macro or inline function that achieves the same effect, except it will only work for one type per macro.

// C99
static inline int maxi(int x, int y) { return x > y ? x : y; }

In C89/C90, I can't think of any way to write the macro in such a way that it won't evaluate x or y twice.

like image 188
Dietrich Epp Avatar answered Oct 19 '22 04:10

Dietrich Epp


The ({ ... }) construct is a gcc extension.

So is the typeof operator.

A MAX macro (note the conventional use of all-caps) is easy enough to write:

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

It does evaluate one of its arguments more than once, so you shouldn't invoke it as, for example, MAX(x++, y--). The use of all-caps serves to remind the user that it's a macro, not a function, and to be careful about arguments with side effects.

Or you can write a function (perhaps an inline one) for each type.

like image 26
Keith Thompson Avatar answered Oct 19 '22 03:10

Keith Thompson