Why use Macros in C? [duplicate]

Solution 1:

It's not exactly search and replace, it's token expansion. C macros are what every other kind of macro is in the computing world: a way to write something short and simple and have it automatically turn into something longer and more complicated.

One reason macros are used is performance. They are a way of eliminating function call overhead because they are always expanded in-line, unlike the "inline" keyword which is an often-ignored hint to the compiler, and didn't even exist (in the standard) prior to C99. For example, see the FD_ family of macros used in conjunction with the fd_sets used by select and pselect. These fd_sets are really just bitsets, and the FD_ macros are hiding bit twiddling operations. It would be annoying to write out the bit twiddling yourself every time, and a function call would be a lot of overhead for such a fast operation if it were not inlined.

Also, macros can do some things that functions cannot. Consider token pasting. Since the preprocessor runs before the compiler, it can make new identifiers for the compiler to use. This can give you a shorthand way to create lots of similar definitions, e.g.

#define DEF_PAIR_OF(dtype) \
  typedef struct pair_of_##dtype { \
       dtype first; \
       dtype second; \
  } pair_of_##dtype##_t 

 DEF_PAIR_OF(int);
 DEF_PAIR_OF(double);
 DEF_PAIR_OF(MyStruct);
 /* etc */

Another thing it can do that a function could not is turn compile-time information into runtime information:

#ifdef DEBUG
#define REPORT_PTR_VALUE(v) printf("Pointer %s points to %p\n", #v, v)
#else 
#define REPORT_PTR_VALUE(v)
#endif

void someFunction(const int* reallyCoolPointer) {
  REPORT_PTR_VALUE(reallyCoolPointer);
  /* Other code */
}

There's no way that a function could use the name of its parameter in its output like the macro can. This also demonstrates compiling out debug code for release builds.

Solution 2:

One reason is until C99, the inline keyword was not standard in the C language. Thus macros allowed you to inline small functions. They also in some ways work like templates, ie. you don't have to specify types in the macro definition eg:

#define MAX(x,y) ((x) > (y) ? (x) : (y))

This macro is complient with integers, doubles, floats etc.

Solution 3:

Macros are expanded at compilation time. You are correct that they are often abused but a classic example in C would be to have a macro for writing debugging messages which (when debug mode is turned off at compilation time) doesn't generate any code so causes no slowdown.

Solution 4:

Sometimes you want to do logging, but only in debug mode. So you write something like:

#ifdef DEBUG
#define LOG_MSG(x) printf(x);
#else
#define LOG_MSG(X)
#endif

Sometimes you just want to turn something off or on based on a compile-time switch. E.g., my company does some co-branding of our product and partners ask to turn things off. So we'll do something like:

#ifndef SPECIAL_PARTNER_BUILD
    DoSomethingReallyAwesome();
#endif

Then build with -DSPECIAL_PARTNER_BUILD when giving the partner drops.

Among many other possible reasons.

Sometimes you just want to save typing for things you do over and over again. Some people take this to far (cough MFC cough) and write what amounts to their own language in Macros to abstract away a difficult API. This makes debugging a frikkin' nightmare.