Wednesday, August 31, 2022

[SOLVED] GCC recommends a strange implementation for max macro

Issue

so , I was reading GCC documentation until I reached Statements and Declarations in Expressions section 6.1 , href="https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html#Statement-Exprs" rel="nofollow noreferrer">follow this link to reach the section I am talking about.

I came to these strange lines where GCC states that

This feature is especially useful in making macro definitions “safe” (so that they evaluate each operand exactly once). For example, the “maximum” function is commonly defined as a macro in standard C as follows:

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

But this definition computes either a or b twice, with bad results if the operand has side effects. In GNU C, if you know the type of the operands (here taken as int), you can avoid this problem by defining the macro as follows:

#define maxint(a,b) ({int _a = (a), _b = (b); _a > _b ? _a : _b; })

from my understand , GCC recommends knowing the type of the arguments, now I have many questions in my head.

  1. why do I have to know the type of the arguments ? I mean C macros are just like text replacements , so I think max(a,b) will work just fine with any primitive data type whether it's integer, float, double, etc..

  2. I don't know how will maxint(a,b) work , I mean it's a strange signature of ternary operator , I mean for example in the next lines of code:

    #include <stdio.h>
    
    #define maxint(a,b) \
      ({int _a = (a), _b = (b); _a > _b ? _a : _b; })
    
    int main()
    {
        int x = 5;
        int y = 10;
        int z = maxint(x , y);
        printf("z = %d",z);
    }
    

z value will be 10 , which is a correct answer, and the next lines are the lines generated after preprocessing done by the compiler of the above code:

int main()
{
    int x = 5;
    int y = 10;
    int z = ({int _a = (x), _b = (y); _a > _b ? _a : _b; });
    printf("z = %d",z);
    return 0;
}

my problem is in this line int z = ({int _a = (x), _b = (y); _a > _b ? _a : _b; }); , how does this line evaluate z to be 10 , I mean It's just a block of lines , there is no return value. I only see this line when evaluating at runtime to be

int z = ({int _a = (5), _b = (10); 10; }); as whole ternary operation will be replaced by the value 10,as (5 > 10 ? 5 : 10) will be replaced by 10, which doesn't make sense to me to assign a block of code to a primitive data type (which is z in my case)

  1. they said in the quoted lines above

But this definition computes either a or b twice

talking about this macro max(a,b) , I don't understand how does this macro computes either a or b twice and how did macro maxint(a,b) solve this problem ?


Solution

why do I have to know the type of the arguments ?

To evaluate the arguments once, in assignment.

( And you don't, you can use another gcc extension __auto_type or __typeof__. )

I mean it's a strange signature of ternary operator

It's a gcc extension called statement expression https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html .

It's just a block of lines , there is no return value

And from that documentation: The last thing in the compound statement should be an expression followed by a semicolon; the value of this subexpression serves as the value of the entire construct. The value of _a > _b ? _a : _b; is the last, and it serves as the "return value" of ({...}).

how does this macro computes either a or b twice and how did macro maxint(a,b) solve this problem ?

Is explained in macro pitfalls in gcc documentation https://gcc.gnu.org/onlinedocs/cpp/Duplication-of-Side-Effects.html#Duplication-of-Side-Effects .

Many C programs define a macro min, for “minimum”, like this:

#define min(X, Y) ((X) < (Y) ? (X) : (Y))

When you use this macro with an argument containing a side effect, as shown here,

next = min (x + y, foo (z));

it expands as follows:

next = ((x + y) < (foo (z)) ? (x + y) : (foo (z)));



Answered By - KamilCuk
Answer Checked By - Mildred Charles (WPSolving Admin)