2
votes

i'm trying to define the following macro:

#define UTF8_2B(c) if((0xc0 & c) == 0xc0){return 1;}

But i'm met with the error:

expected expression before ‘if’

The macro is called like so:

int i = UTF8_2B(c);

Where c is an unsigned char read from a file.

Why does this happen? Can you not use if else statements in macros? Also, I've read that it's not a good idea to use semicolon in your macros, but i didn't understand why. I'm new to c so the more thorough the answer the better.

3
How do you use the macro? (And, perhaps more importantly: What do you want to achieve?) - M Oehm
show the context where you're calling this macro - Jean-François Fabre
Macros do text substitutions; you couldn't write variable = if (condition) … directly, so you can't use a macro that does it either. You're missing the else value too. And return is wholly inappropriate in context. Remember: macro is text substitution. After preprocessing, the code must be valid C. - Jonathan Leffler
Not only that, even the logic is wrong. What should happen in the else case? - Jens Gustedt

3 Answers

4
votes

C (and C++) preprocessor macros are essentially "copy-paste" with argument substitution. So your code becomes:

int i = if((0xc0 & c) == 0xc0){return 1;}

And this is invalid syntax.

2
votes

You're assigning the result of your macro to a variable. You cannot do that with the current macro (return returns from the current function, and doesn't return something to be assigned to i: so not what you want).

If you're using gcc, you can view what your pre-processed code looks like with the -E command line.

So you can use if in macros, but not in macros that are used like functions, which are supposed to return a value.

Moreover:

  • if c is a complex expression, operator precedence could make the macro generate wrong code
  • the macro should provide a way to require semicolon, so IDEs and human readers see that as a normal function

I'd propose a simple test instead (which yields 1 if true, 0 otherwise), which meets the "need semicolon" standard and is safe to use with a complex c expression:

#define UTF8_2B(c) ((0xc0 & (c)) == 0xc0)
2
votes

The ternary operator exists for this purpose. Assuming you want 1 if true and 0 if false, the correct macro is:

 #define UTF8_2B(c) (((c) & 0xC0) == 0xC0 ? 1 : 0)

Now you can assign the result. Using return in a macro will return from the enclosing function, not from the macro, and is almost always a bad idea.