Main C Header File Syntax
I am considering the math.h header included in my IDE. I see the following code, which I don't understand the syntax. This is basic stuff, but can anyone explain to me how it works?
#define isgreater(x,y) \
(__extension__ ({__typeof__(x) __x = (x); __typeof__(y) __y = (y); \
!isunordered(__x,__y) && (__x > __y);}))
So, for example, what does it do when you start something with double underscores, for example: Does __typeof
this allow undefined sizes? so this macro can take values of different sizes?
Is the forward slash only line breaks in the source?
what does it do __extension__
?
thank
source to share
You can see the use of several compiler extensions:
-
__typeof__
is a GCC extension that allows you to get the type of a variable (and use it in a variable declaration); it exists, so the macro can handle any typex
andy
. - The second GCC extension turns
({ ... })
into an expression that evaluates the value of the last statement within it; this allows you to declare variables inside that block, which avoids checking the two operandsx
and twicey
. The resultsx
andy
(which might be somethingi++
you don't want to evaluate twice) are stored in two temporary variables__x
and__y
, and then those two temporary variables are used instead ofx
andy
to avoid double estimation. -
__extension__
is an extension that suppresses the warning you might otherwise use the above extension.
And yes, it \
just defines the definition of multiple lines of a macro ( \
concatenates the lines and is executed very early in the compilation process, even before the definitions of macros and preprocessors are discussed).
The whole point of this rigmarole is to avoid being evaluated x
and y
doubled. If you did
bool g = isgreater(x++, y++);
And you didn't use this trick, you get
bool g = !isunordered(x++, y++) && (x++ > y++);
This will lead to the fact that x
and y
will double every time, and not once, as you planned. Instead, with a trick, you end up with something like (using better names for temporary variables)
int tmpx = x++;
int tmpy = y++;
bool g = !isunordered(tmpx, tmpy) && (tmpx > tmpy);
(if x
and y
are integers), which is correct and avoids double increments. This goes for other things as well, like function calls:
isgreater(launch_missiles(3), launch_missiles(4));
Without the trick, you end up launching 14 missiles instead of 7, which would be disastrous.
source to share
This reformatting of the definition might help you
#define isgreater(x,y) \
( \
__extension__ ( \
{ \
__typeof__(x) __x = (x); \
__typeof__(y) __y = (y); \
!isunordered(__x,__y) && (__x > __y); \
} \
) \
)
__extension__
marks code that uses gcc extension to the standard ANSI C. The expansion in this case is the operator __typeof__
that provides the type of a variable at compile time and is used to declare __x
and __y
with the same types as x
and y
. Then it goes ahead and checks that the pair of values is ordered (which isunordered
is a Math library function) and is __x
greater than __y
.
source to share