tags:

views:

261

answers:

7

What error is thrown when macro and function conflict in C arises? Is it a macro processor error or does this error occur due to some language violation?

For example, in this code:

#include <stdio.h>
#define MAX(i, j) (i>j)? i : j

int MAX(int i, int j){
  return (i>j) ? i : j;
}

int main(){
  int max = MAX(5, 7);
  printf("%d",max);
  return 0;
}

The program throws a compile time error. But I don't understand whether it was some language violation or macro expansion error or something else.

+1  A: 

As preprocessor macros are only used for processing plain text, these conflicts would always cause a compile time error.

Lauri
+1  A: 

The pre-processing occurs first, so line 4 will become:

int (int i>int j)? int i : int j

which is not valid C.

Simon Nickerson
+12  A: 

During the preprocessing phase the code gets converted to :

int (int i>int j)? int i : int j{
  return (i>j) ? i : j;
}

int main(){
  int max = (5>7)? 5 : 7;
  printf("%d",max);
  return 0;
}

...which, as anyone can tell, is an illegal C code.

(With gcc you could use an -E option to see the preprocessed version of the file.)

missingfaktor
+1 "as anyone can tell..." if only!
Autopulated
+2  A: 

You'll get a compiler error because the macro will be expanded before compilation is attempted.

This is a really nasty problem, and one for which there is not really a solution. For this reason you should avoid defining un-scoped, function-like macros as much as possible, especially in headers that are widely included. Like everything, they have their place, but you need to be careful not to overuse them.

jkp
+3  A: 

Others have pointed out the problem but gave no solutions. The best would be to just use MAX as an inline function. If the macro is in a header, put the inline function definition in the header instead. If you still wish to use a macro (or using an old C compiler which doesn't support inline functions) you can define the function this way:

int (MAX)(int i, int j){
    return (i>j) ? i : j;
}

This will prevent the troubling macro expansion and provide MAX as an external function. This will enable you to, for example, assign its address to a variable.

extern int (MAX)(int, int);
...
int (*max_func_ptr)(int, int);
...
max_func_ptr = MAX;
Tim Schaeffer
tomlogic
+2  A: 

There is no error that occurs specifically to call out that there's a conflict. What happens is that the macro processing occurs first, so in a sense macro definitions respect no name spaces - this is one of the main reasons why macros considered bad form and should be avoided except as a last resort. See this question for an example of a situation where someone's perfectly valid use of the name BitTest for a template was screwed over because someone else decided to create a macro using that name to 'alias' another name: http://stackoverflow.com/questions/2232580/win32-bittest-bittestandcomplement-how-to-disable-this-junk

So in your example, as other answers have mentioned, once the preprocessing step has occurred, you'll end up with something like the following snippet being passed to the C compiler in place of your function definition:

int (int i>int j)? int i : int j{
  return (i>j) ? i : j;
}

This isn't valid C, so you'll get a compiler error that might say (from GCC 3.4.5):

error: syntax error before "int"

or (from MSVC 9):

error C2059: syntax error : 'type'

Which really isn't much help, because when you look at the line the error is refering to in your editor, it'll still look like:

int MAX(int i, int j){

which looks valid.

There are several techniques that are used to help avoid the problem:

  • use all caps for macro names and only macro names; this is a convention that is largely followed to keep the macro namespace separate from names used for other things

  • put parens around names that you don't want expanded as macros (this only works for 'function-like' macros). If your example had been written as follows:

    int (MAX)(int i, int j){
      return (i>j) ? i : j;
    }
    

    it would not have resulted in the macro expansion. However, I don't see people doing this very often. One set of utility routines I have uses this technique to protect against macro name collisions, and I often get questions about why all the function names are in parens. Also several editors get confused with function navigation for those files.

  • avoid using macros; as I mentioned this is one reason that macros are considered bad form. There are other reasons including that they can easily cause the expanded form to produce bad or unexpected expressions if you don't properly use parens around macro parameters or by evaluating a macro parameter that has side effects more than once.

    Use inline functions or function templates instead if you can.

Michael Burr
+1, Very nicely explained.
missingfaktor
A: 

out of curiosity, when would this arise in code? i've seen the (MAX)(int i, int j) style function declarations in some other code as well (where there exists a function-like macro called MAX in the code), yet i can't quite figure out why any programming pattern would have such a phenomenon.

is there a common situation (even if bad form), where this pattern arises?

Murat
It's not good form to answer someone with a question ;)
robinjam