Confused by Squaring MACro Sqr in C

Confused by squaring macro SQR in c

SQR(1+1) expands to 1+1*1+1 which is 3, not 4, correct?

A correct definition of the macro would be

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

which expands to (1+1)*(1+1) and, more important, shows you one of the reasons you shouldn't use macros where they aren't needed. The following is better:

inline int SQR(int x)
{
return x*x;
}

Furthermore: SQR(i++) would be undefined behavior if SQR is a macro, and completely correct if SQR is a function.

in c how preprocessor(#) get evaluated ? not understanding the output of this program

It is because 5 + 1 * 5 + 1 is 11. The multiplication comes first, 1 * 5, so you're left with 5 + 5 + 1 => 11.

To get 36, change your macro to:

#define s(x) ((x)*(x))

Which will then become ((5 + 1) * (5 + 1)) => (6 * 6) => (36)

Square of a number being defined using #define

square is under-parenthesized: it expands textually, so

#define square(x) x*x
...
i=4/square(4);

means

i=4/4*4;

which groups as (4/4) * 4. To fix, add parentheses:

#define square(x) ((x)*(x))

Still a very iffy #define as it evaluates x twice, so square(somefun()) calls the function twice and does not therefore necessarily compute a square but rather the product of the two successive calls, of course;-).

How MACROS work in C?

It's basically, find and replace before compiling. Your code becomes

int main(){
int a=5;
printf("%d",a+3*a-2);
return 0;
}

instead of #define mul(p,q) p*q you should do #define mul(p,q) ((p)*(q)). Then your code would become as below and you would get the expected answer.

int main(){
int a=5;
printf("%d",((a+3)*(a-2)));
return 0;
}

Confusion with Macro expansion

This is really undefined behavior (and should not be relied on on another compiler or even the next run of the same compiler) since it increases the same variable twice in the same statement without a sequence point, but this is what seems to happen in this case;

#define SQUARE(x) ( x * x )
j = SQUARE( i++ ) ;
k = SQUARE( ++i ) ;

will expand to

j = (i++ * i++);     // Compiler could do i * i, then increment twice, or use i * (i + 1), or...  

k = (++i * ++i); // Same as above

As this is undefined behaviour, the compiler is free to do whatever it wants (old versions of gcc made the program launch nethack ;-). To be more precise: The compiler is free to assume undefined behaviour won't ever be called upon, and just make sure the code works correctly in "normal" cases. What happens in unexpected cases is anybody's bet.

What is the order of execution in these type of cases?

With #define square(x) x*x, this square(2+3) turns into

2+3*2+3. Which of course causes unexpected results because of preference of * over +. The problem does not occur with *, because the order of preference in that case does not matter.

You probably want #define square(x) (x)*(x), in order to get (2+3)*(2+3).

Or, less vulnerable to indirect problems of similar nature,

#define square(x) ((x)*(x)), in order to get ((2+3)*(2+3)).

Even better, because macros really offer a lot of traps like this one to get caught in, you should simply use a cleanly defined function. With modern compilers most of the reasons to use macros are obsolete.

What is better, macros or inline functions for square or sqrt of constants?

Because those constants are true constants (not to be confused with const variables). You'd want your code to use them directly at runtime, and you certainly do not want to have a call to the sqrt or pow function that is basically useless because you already know the result at compile time.

If you want to be sure that there is no useless calls, you should use the macros with C pre-processor for this. And you are not wrong, the C compilers can sometimes make us feel in the 80s. There is many other more modern programming languages available.

However as the compilers are getting more modern at optimizing prorgrams it is also possible that the compiler might inline functions then pre-compute them at compile time. The only way to know if it is possible is to test and look at the generating assembly. For instance in my test program :

static inline int twice(int x)
{
return 2*x;
}

int main()
{
int i = twice(2);
i += twice(4);
printf("Result is %d\n", twice(i));
return 0;
}

Compiles with latest gcc and -Os turned on to :

main:
sub rsp, 40
.seh_stackalloc 40
.seh_endprologue
call __main
lea rcx, .LC0[rip]
mov edx, 24
call printf
xor eax, eax
add rsp, 40
ret

As you can see, the result, 24 is pre-computed in the assembly code. With double type it's less obvious to proove because of how floating points number doesn't immediately appear in the assembly, however I checked and the optimisation is also made. Then it is not neccessary to use the C pre-processor for constants anymore. But if you want performance, always check the assembly code.



Related Topics



Leave a reply



Submit