Göksenin Cakir
Göksenin Cakir

Reputation: 187

Unwanted (or erratic) result of macro function

The code below with the inputs 2, 3, 10 is intended to give the 12.5 as the result.([sum(2,3,10)(=15) + largest(2,3,10)(=10)] / smallest(2,3,10)(=2)) But it outputs 2.000 as the result, which is unwanted and wrong. Am I making a precedence error or what kind of a mistake am I making?

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <ctype.h>
#define MIN( a, b ) ( ( a < b ) ? (a) : (b) ) // Why are the parantheses imporant?
#define MAX( a, b ) ( ( a < b ) ? (b) : (a) )
#define LARGEST( a, b, c ) ( MAX( a, b ) < c ) ? c : ( MAX( a, b ) )
#define SMALLEST( a, b, c ) ( a < MIN( b, c ) ) ? a : ( MIN( b, c ) )
#define SUM( a, b, c ) ( (a + b + c) )
#define EXPR( a, b, c ) ( (LARGEST( a, b, c ) + SUM( a, b, c ) ) /  SMALLEST( a, b, c ) ) 

int main(){
    float a, b, c;
    printf("Enter three integers!\n");
    scanf(" %f", &a);
    scanf(" %f", &b);
    scanf(" %f", &c);
    printf("The result is %f.\n", EXPR(a, b, c));   
    return 0;
}

Upvotes: 3

Views: 169

Answers (2)

to see the actual code generated by the preprocessor merely execute this command

gcc -E main.c 

we will get (just the last part of the output from the last command )

#include <stdio.h>

int main()
{
    float a, b, c;
    printf("Enter three integers!\n");
    scanf(" %f", &a);
    scanf(" %f", &b);
    scanf(" %f", &c);
    printf("The result is %f.\n", ( (( ( ( a < b ) ? (b) : (a) ) < c ) ? c : ( ( ( a < b ) ? (b) : (a) ) ) + ( (a + b + c) ) ) / ( a < ( ( b < c ) ? (b) : (c) ) ) ? a : ( ( ( b < c ) ? (b) : (c) ) ) ));
    return 0;
}

This is a little bit complicated

 ( (( ( ( a < b ) ? (b) : (a) ) < c ) ? c : ( ( ( a < b ) ? (b) : (a) ) ) + ( (a + b + c) ) ) / ( a < ( ( b < c ) ? (b) : (c) ) ) ? a : ( ( ( b < c ) ? (b) : (c) ) ) )

My first guess was as I stated in the comment was precedence

so let's take the left operand in / operator and ignore the rest for a moment to see the problem

(( ( ( a < b ) ? (b) : (a) ) < c ) ? c : ( ( ( a < b ) ? (b) : (a) ) ) + ( (a + b + c) ) )
                                        |-----------------------------------------------|
                                            the sum of the three operator will be added to the statement of the false condition ONLY (which is if a  or b is the largest in this case) first and then we will evaluate the ?: because as you know the + is higher than ?: in table precedence 

so let's call the left block just treated (just above) LeftBlock to make things simple for the next analysis

So combined with the right operand of / operator (or what is left from the whole statement ) we will get

LeftBlock / ( a < ( ( b < c ) ? (b) : (c) ) ) ? a : ( ( ( b < c ) ? (b) : (c) ) )

now the / is higher than the ?: operator in precedence so this expression will be first evaluated

LeftBlock / ( a < ( ( b < c ) ? (b) : (c) ) ) ? a : ( ( ( b < c ) ? (b) : (c) ) )
|--------------------------------------------| 
          this is the condition for the ?: operator instead of only ( a < ( ( b < c ) ? (b) : (c) ) ) which is WRONG 

As you can see the lack of parentheses leads to undesired result !!

There are many others pitfalls about macros that you should avoid you can check some of them from this link!

Finally I think I deobfuscated the problem !! :)

Upvotes: 9

Iharob Al Asimi
Iharob Al Asimi

Reputation: 53026

Because macro expansions substitute each ocurrence of the macro textualy, for example consider this simple macro

#define SQR(x) x * x

this macro when used like this

double x = SQR(1.0 + 2.0);

will expand to

double x = 1.0 + 2.0 * 1.0 + 2.0;

which yeilds 5.0, if you add the parentheses, they will be inserted too

#define SQR(x) (x) * (x)

and then it would expand to

double x = (1.0 + 2.0) * (1.0 + 2.0);

which yields 9.0.

Upvotes: 4

Related Questions