简体   繁体   中英

macro hazards in c preprocessor

I have define the following macro,

#define abss(a) a >= 0 ? a : -a

while invoking this with,

int b=-1;
int c = abss(b);
printf("%d\n",c);

it should replaced in the form b >= 0 ? b : --b, which should output -2, but it outputs in my Bloodshed/DevC++ compiler 1.

I am analyzing C language for examination purpose, so I have to know what actually happens to the above case in C. Is the output result 1 is for CPP compiler I am using or what???

Your code

int b=-1;
int c = abss(b);
printf("%d\n",c);

gets translated by the preprocessor to:

int b=-1;
int c = b >= 0 ? b : -b;
printf("%d\n",c);

(the int b=-1 is in the C domain whereas the abss(b) gets expanded by the preprocessor before the compiler gets to int b=-1 )

Why on earth do you think it should output -2?

#define abss(a) a >= 0 ? a : -a

so this: int c = abss(b)

becomes int c = b >= 0 ? b : -b

and b is -1, so that will evaluate to 1

by the way, you should bracket every use of a macro parameter, as you may get passed such things as x + 1. which would evaluate rather strangely.

Not to mention the results of abss(++x)

#define neg(a) -a

int b = -1;
neg(b);

In the above case, the macro is expanded to -b by the preprocessor, which will result in the value of 1. The preprocessor won't even be aware that the sign of the content of b is negative, so where should the second - come from to form a prefix decrement operator?

Even if you wrote it like this:

 neg( -b );

Macro replacement is done on token level, not as a textual search & replace. You would get the equivalent of - ( -b ) , but not --b .

Edit: The manual you link to in other comments is outdated (does not even address the C99 standard), and is dangerously bad. Just skimming through it I found half a dozen of statements that will make you look real stupid if you assume them to be correct. Don't use it, other than to light a fire.

Your macro expands to

b >= 0 ? b : -b;

Not to b >= 0 ? b : --(-b); b >= 0 ? b : --(-b); or whatever it is you expected.

Are you suggesting that

int x = -4;
-x; 

should decrement x ?

Bottom line - avoid macro use when possible.

The macro processor will never attach two adjacent tokens together, even if there is no whitespace between them, so indeed, as other posters have mentioned, your macro expands to - b , or 1.

If you want two tokens to become one when expanded by the preprocessor, you have to use the token pasting operator ## , something like

#define abss(a) a >= 0 ? a : - ## a

this will indeed do what you want, in the sense that the negative sign and the variable will form one token. Unfortunately (or fortunately, depending on how you look at it!) the pasted token "-b" will be invalid, and the expansion will not compile.

This macro

#define abss(a) a >= 0 ? a : -a

is indeed hazardous, but the hazards are not where you think they are. The expression from your post

int c = abss(b);

works perfectly fine. However, consider what happens when the expression is not a simple variable, but is a function that is hard to calculate, or when it is an expression with side effects. For example

int c = abss(long_calc(arg1, arg2));

or

int c = abss(ask_user("Enter a value"));

or

int c = abss(b++);

If abss were a function, all three invocations would produce good results in predictable time. However, the macro makes the first call invoke long_calc and ask_user twice (what if the user enters a different number when prompted again?), and it post-increments b twice.

Moreover, consider this seemingly simple expression:

int c = abss(b) + 123;

Since + has a higher precedence than ? : ? : , the resulting expansion will look like this:

int c = b >= 0 ? b : -b + 123;

When b is positive, 123 will not be added, so the meaning of the expression will change dramatically!

This last shortcoming can be addressed by enclosing the expression in parentheses. You should also enclose in parentheses each macro argument, like this:

 #define abss(a) ((a) >= 0 ? (a) : -(a))

The reason for you getting the behaviour is preprocessor will just replace a with b and so effectively your code after preprocessing will be like

b >= 0 ? b : -b

and not

b >= 0 ? b : --b

So, when if b = -1, then it will effectively be considered as -(-1) and thus becomes 1.

You can check the preprocessor output and see it for yourself.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM