tags:

views:

999

answers:

12

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?

+14  A: 

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.

DeusAduro
You should have parens around a and b on the right side.
jeffamaphone
This is a good point. Macros don't create an extra stack frame (unless of course you call a function from one).
harpo
Are inlines guaranteed to be inlined now?
Nosredna
@Nosredna: No, they aren't. In GCC anyway the compiler takes them as a strong hint but will still ignore you when it thinks it knows best.
Mike McQuaid
No. If anything, a modern compiler is more likely to ignore inline requests because of improved optimizing behavior within the compiler.
Tyler McHenry
Microsoft's compiler lets you say __forceinline to override the compiler. But you probably shouldn't be using it ever. Unless you're the kind of person who can look at the disassembly and say for certain one is better than the other. http://msdn.microsoft.com/en-us/library/z8y1yy88.aspx
jeffamaphone
Well, I would look at the assembly, but more importantly, I time everything I do in C/C++ because the only thing I write in it anymore is DSP code.
Nosredna
+8  A: 

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.

Mike McQuaid
+8  A: 

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.

jeffamaphone
A: 

In performance intense scenarios, you can use macros to create "automatic" loop unrolling. Modern compilers probably do a better job with this though, but that used to be a useful application for it.

korona
+1  A: 

For one thing, in C macros are used to define constants, include header files, conditional compilation, etc. It would be nigh impossible to program without them.

J Cooper
Not all preprocessor directives are macros. #include is not a macro.
Tyler McHenry
+4  A: 

Macros can have many different uses other than function like things.

It is very useful to use macros for anything magic number or string related.

#define MY_MAGIC_NUM 57

/*MY_MAGIC_NUM used all through out the code*/
lillq
This sort of thing can increase the readability of your code. Also, it is pretty useful when defining the maximum size of a non-heap allocated array.
Whisty
Why is this preferred to using a constant?
Alan Storm
Wait, scratch that, I just realized constants ARE using macros in C.
Alan Storm
An array must be declared with a compile time constant expression. Unlike C++, `const` in C is never a compile time constant. (In C99, arrays inside functions can be declared with a variable size).
Whisty
No, there's a distinct difference between a global constant variable and a macro. Namely, the value of the macro is substituted into the code before compilation, while the value of the global constant is stored in the executable and loaded into memory and retrieved at execution time (optimizations notwithstanding). You can take the address of a global constant, but you cannot take the address of a macro.
Tyler McHenry
Ah, thanks for that clarification Tyler.
Alan Storm
+11  A: 

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.

Tyler McHenry
A: 

On Macros, the function's code gets inserted into the caller's code stream. This can, depending on many other things, improve performance, because the optimizer can procedurally integrate the called code — optimize the called code into the caller But beware, because on macros argument types are not checked. A good reference to inline functions (if you are also using C++) and a little bit of macros is. http://www.parashift.com/c++-faq-lite/inline-functions.html#faq-9.5

Diego Dias
A: 

C macros can generate code at compile time. This can be (ab)used to effectively create domain-specific languages with new keywords and behaviors.

I posted one of my favorite examples, a macro to implement coroutines in C, in another SO question.

Dour High Arch
A: 

The compiler often knows details about the target machine, so you can use conditional compilation to have one piece of code for big endian processors and another for little endian processors. That keeps the code from being bloated with code that's designed for a different processor.

A similar case is when you have assembly code for one particular system but C code for other systems.

Nosredna
A: 

I think that biggest advantage comes when used as "seeting file"

#define USE_FAST_AGORHITM
//#define USE_SLOW_ONE

And global "constants"

#define MAX_NUMBER_OF_USERS 100000

There are programs written mostly in macros (Check for instance Brian Gladman's AES implementation http://gladman.plushost.co.uk/oldsite/cryptography%5Ftechnology/index.php )

ralu
A: 

We used this type of macro in our code:

// convenience macros for implementing field setter/getter functions
#ifndef CREATE_GET_SET
#define CREATE_GET_SET(PREFIX, FIELD_NAME,FIELD_DATATYPE) \
  protected:\
    FIELD_DATATYPE PREFIX ## FIELD_NAME;\
  public:\
  inline FIELD_DATATYPE get ## _ ## FIELD_NAME(void) const\
  { \
    return(PREFIX ## FIELD_NAME); \
  } \
  inline void set ## _ ## FIELD_NAME(FIELD_DATATYPE p) \
  { \
    PREFIX ## FIELD_NAME = p; \
  }
#endif

within a class/structure you would define a variable:

CREATE_GET_SET(_, id, unsigned int);

This would define your variable and create the generic getter/setter for the code. It just makes for cleaner, consistent code generation for get/set. Sure, you can write it all out, but that's a lot of boilerplate type code NOTE: this is just one of a couple macros. I didn't post them all. You wouldn't handle say "char *" this way (where you want the set to strncpy or strcpy the data). This was just a simple demo of what you could do with a macro and some simple types.

jinxx0r