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?
-
1Using macros the way you suggest (modifying existing source code by redefining existing tokens instead of actually changing the code) is a really bad idea, unless you're just talking about changing the values of #defined constants.Tyler McHenry– Tyler McHenry2009年08月31日 16:53:09 +00:00Commented Aug 31, 2009 at 16:53
-
2Dupe of stackoverflow.com/questions/653839/what-are-c-macros-useful-for among many, many others.anon– anon2009年08月31日 17:01:42 +00:00Commented Aug 31, 2009 at 17:01
-
2Certainly similar to those questions, but none that came up in search directly asked what made macros superior to just defining a function to do the work for you. I'm much happier with the answers here than in that other thread.Alana Storm– Alana Storm2009年08月31日 17:23:36 +00:00Commented Aug 31, 2009 at 17:23
-
All of the answerrs that appear here have appeared in similar questions regarding macros - there are, after all, a limited number of things you can do with macros.anon– anon2009年08月31日 17:31:05 +00:00Commented Aug 31, 2009 at 17:31
-
I disagree Neil. Quick example, this is the only thread that someone noted that macros can be used to avoid the creation of a new stack-frame, an answer that came about because the context of my question was different than the other questions.Alana Storm– Alana Storm2009年08月31日 18:39:15 +00:00Commented Aug 31, 2009 at 18:39
11 Answers 11
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.
Comments
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.
8 Comments
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.
2 Comments
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.
2 Comments
inline
, this remains as the only "definitely use this" case?#def ANSWER_TO_EVERYTHING 42
instead of putting 42
everywhere. It's all fine and dandy until when one morning you wake up and realize that your 500k line project now wants to use 56
instead of 42
but instead of using a macro you hardcoded it everywhere, and a simple find and replace won't do because not all 42
's might have been for the same thing and so need to be left as is.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*/
5 Comments
const
in C is never a compile time constant. (In C99, arrays inside functions can be declared with a variable size).C macros can generate code at compile time. This can be (ab)used to effectively create domain-specific languages with new keywords and behaviors.
One of my favorite examples is Simon Tatham’s method of implementing coroutines in C through macros. The simplest macro implemented is:
#define crBegin static int state=0; switch(state) { case 0:
Yes, with an unmatched brace. Other macros will fix that up.
Comments
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.
Comments
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.
Comments
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.
Comments
I think that biggest advantage comes when used as "setting 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://www.gladman.me.uk/cryptography_technology/index.php )
1 Comment
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