liv2hak
liv2hak

Reputation: 14990

MAX using typeof extension of gcc

I have been programming in C for quite a while now.So I decided to learn a bit of advanced C.I heard of gcc compiler extensions.Below I saw a code for the MAX() that I till now has implemented as follows

#define MAX(x,y) ((x) > (y)? (x): (y))

This is the new definition that I found.Unfortunately I can't even understand what the below code does? and why would I do it as below instead of as above?

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

Upvotes: 4

Views: 778

Answers (3)

David Ranieri
David Ranieri

Reputation: 41017

typeof (a) _a = (a);            \
typeof (b) _b = (b);            \

Creates two variables with the same type of a and b to avoid evaluating twice

More info

The most obvious candidate for an inline function is a preprocessor macro. An inline function in GCC will perform as well as a macro, and, additionally, receives type checking. For example, instead of this macro:

#define max(a,b) ({ a > b ? a : b; })

one might use the corresponding inline function:

static inline max (int a, int b)
{
        if (a > b)
                return a;
        return b;
}

Upvotes: 3

unwind
unwind

Reputation: 399881

The advantage is that it avoids evaluating the arguments as many times as the classic macro.

By introducing local variables (using typeof to "clone" the type of the arguments), the actual expressions are only evaluated once, the return value is then simply using the local variable rather than evaluating the input expression again, as the classic macro has to do.

Compare what happens if called like this:

int a = 0, b = 1;
const int c = MAX(++a, ++b);

In the first case, because the input expressions have side-effects, the result will be hard to predict. In the second case, the arguments are only evaluated once so everything behaves as if MAX() was a regular function.

Also, your first macro example is failing to enclose the arguments in parenthesis everywhere, which is dangerous.

Upvotes: 8

Paul R
Paul R

Reputation: 212979

This is an example of a generic macro which will work with different data types, e.g. int or float. So for example:

int i = 10;
int j = 20;
int k = MAX(i, j);

expands to:

int i = 10;
int j = 20;
int k = ({ int _a = (i); int _b = (j); _a > _b ? _a : _b; });

whereas:

float x = 10.0f;
float y = 20.0f;
float z = MAX(x, y);

expands to:

float x = 10.0f;
float y = 20.0f;
float z = ({ float _a = (x); float _b = (y); _a > _b ? _a : _b; });

It will even work with mixed data types, e.g.

int i = 10;
float y = 20.0f;
float z = MAX(i, y);

As well as supporting different data types it also avoids the nasty side effects of simpler macros, e.g.

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

which will behave undesirably if you invoke it as e.g.

int k = MAX(i++, j++);

Furthermore it can be more efficient if you pass an expression as an argument, e.g.

float x = 10.0f;
float y = 20.0f;

float z = MAX(sin(x), sin(y));

since the arguments are only evaluated once.

Upvotes: 3

Related Questions