Take the 2-minute tour ×

I'm programming in C.

I always saw examples and cases where using a macro is better than using function.

Could someone explain me with an example the disadvantage of a macro compared to a function?

share|improve this question
Turn the question on its head. In what situation is a macro better? Use a real function unless you can demonstrate that a macro is better. –  David Heffernan Feb 1 '12 at 22:56

7 Answers 7

up vote 30 down vote accepted

Macros are error-prone because they rely on textual substitution and do not perform type-checking. For example, this macro:

#define square(a) a*a

works fine when used with an integer:

square(5) --> 5*5 --> 25

but does very strange things when used with expressions:

square(1+2) --> 1+2*1+2 --> 1+2+2 --> 5
square(x++) --> x++*x++ --> increments x twice

Putting parentheses around arguments helps but doesn't completely eliminate these problems.

When macros contain multiple statements, you can get in trouble with control-flow constructs:

#define swap(x,y) t=x; x=y; y=t;
if(x<y) swap(x,y); -->
if(x<y) t=x; x=y; y=t; --> if(x<y) { t=x; } x=y; y=t;

The usual strategy for fixing this is to put the statements inside a "do { ... } while(0)" loop.

If you have two structures that happen to contain a field with the same name but different semantics, the same macro might work on both, with strange results:

struct shirt {
    int numButtons;

struct webpage {
    int numButtons;

#define num_button_holes(shirt)  ((shirt).numButtons * 4)

struct webpage page;
page.numButtons = 2;
num_button_holes(page) -> 8

Finally, macros can be difficult to debug, producing weird syntax errors or runtime errors that you have to expand to understand (e.g. with gcc -E), because debuggers cannot step through macros, as in this example:

#define print(x, y)  printf(x y)  /* accidentally forgot comma */
print("foo %s", "bar") /* prints "foo %sbar" */

Inline functions and constants help to avoid many of these problems with macros, but aren't always applicable. Where macros are deliberately used to specify polymorphic behavior, unintentional polymorphism may be difficult to avoid. C++ has a number of features such as templates to help create complex polymorphic constructs in a typesafe way without the use of macros; see Stroustrup's The C++ Programming Language for details.

share|improve this answer
What's with the C++ advertisement? –  Pacerier Sep 27 '13 at 8:58
Agree, this is a C question, no need to add bias. –  ideasman42 Sep 10 at 2:55
C++ is an extension of C that adds (among other things) features intended to address this specific limitation of C. I'm no fan of C++, but I think it is on-topic here. –  D Coetzee Sep 16 at 22:30

The current answers mostly explain the problems with macros, but its possible to write macros that avoid side-effects with multiple instantiation of arguments.

C11 Genetrics

If you like to have square macro that works with various types and have C11 support, you could do this...

inline float           _square_fl(float a) { return a * a; }
inline double          _square_dbl(float a) { return a * a; }
inline int             _square_i(int a) { return a * a; }
inline unsigned int    _square_ui(unsigned int a) { return a * a; }
inline short           _square_s(short a) { return a * a; }
inline unsigned short  _square_us(unsigned short a) { return a * a; }
/* ... long, char ... etc */

#define square(a)                        \
    _Generic((a),                        \
        float:          _square_fl(a),   \
        double:         _square_dbl(a),  \
        int:            _square_i(a),    \
        unsigned int:   _square_ui(a),   \
        short:          _square_s(a),    \
        unsigned short: _square_us(a))

Statement expressions

This is a compiler extension GCC and Clang both support; https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html#Statement-Exprs

#define square(a_) __extension__ ({  \
    typeof(a_) a = (a_); \
    (a * a); })

So the disadvantage with macros is you need to know to use these to begin with, and that they aren't supported as widely.

One benefit is (in this case), is you can use the same square function for many different types.

share|improve this answer

Functions do type checking. This gives you an extra layer of safety.

share|improve this answer

one drawback to macros is that debuggers read source code, which does not have expanded macros, so running a debugger in a macro is not necessarily useful. Needless to say, you cannot set a breakpoint inside a macro like you can with functions.

share|improve this answer

Side-effects are a big one. Here's a typical case:

#define min(a,b) (a < b ? a : b)


gets expanded to:

(x++ < y ? x++ : y)

x gets incremented twice in the same statement. (and undefined behavior)

Writing multi-line macros are also a pain:

#define foo(a,b,c)  \
    a += 10;        \
    b += 10;        \
    c += 10;

They require a \ at the end of each line.

Macros can't "return" anything unless you make it a single expression:

int foo(int *a, int *b){
    return a[0] + b[0];

Can't do that in a macro unless you use GCC's expression statement. (EDIT: You can use a comma operator though... overlooked that... But it might still be less readable.)

Order of Operations: (courtesy of @ouah)


min(x & 0xFF, 42)

gets expanded to:

(x & 0xFF < 42 ? x & 0xFF : 42)

But & has lower precedence than <. So 0xFF < 42 gets evaluated first.

share|improve this answer
and not putting parentheses with macro arguments in the macro definition can lead to precedence issues: e.g., min(a & 0xFF, 42) –  ouah Feb 1 '12 at 23:01
Ah yes. Didn't see your comment while I was updating the post. I guess I'll mention that too. –  Mysticial Feb 1 '12 at 23:07

Example 1:


int main() {
  int x = 2;
  int y = SQUARE(x++); // Undefined behavior even though it doesn't look 
                       // like it here
  return 0;


int square(int x) {
  return x * x;

int main() {
  int x = 2;
  int y = square(x++); // fine
  return 0;

Example 2:

struct foo {
  int bar;

#define GET_BAR(f) ((f)->bar)

int main() {
  struct foo f;
  int a = GET_BAR(&f); // fine
  int b = GET_BAR(&a); // error, but the message won't make much sense unless you
                       // know what the macro does
  return 0;

Compared to:

struct foo {
  int bar;

int get_bar(struct foo *f) {
  return f->bar;

int main() {
  struct foo f;
  int a = get_bar(&f); // fine
  int b = get_bar(&a); // error, but compiler complains about passing int* where 
                       // struct foo* should be given
  return 0;
share|improve this answer

No type checking of parameters and code is repeated which can lead to code bloat. The macro syntax can also lead to any number of weird edge cases where semi-colons or order of precedence can get in the way. Here's a link that demonstrates some macro evil

share|improve this answer
thanks for the link. +1. –  Kyrol Feb 1 '12 at 23:07

Your Answer


