Why use Macros in C?

Alan Storm picture Alan Storm · Aug 31, 2009 · Viewed 60.2k times · Source

Possible Duplicate:
What are C macros useful for?

Every few months I get an itch to go learn some bit of C that my crap college programming education never covered. Today it's macros. My basic understanding of macros is they're a simple search and replace that happens on your code prior to it being compiled. I'm having trouble understanding why you'd use macros. Most of the basic examples I'm looking at are something like

TEST(a,%d);
#define TEST(a,b) printf(" The value of " #a " = " #b " \n", a)

//which expands to 
printf(" The value of a = %d \n",a);

(example from here)

From my newbie point of view, it seems like defining a new function would give you the same results. I can see how historically macros would be useful for modifying a lot of source quickly in the days before easy search and replace, but something tells me I'm missing some bigger point.

So what kind of useful things can macros do for you?

Answer

Tyler McHenry picture Tyler McHenry · Aug 31, 2009

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.