Recommendations for Choosing Between Functions and Macros
Collapse the table of content
Expand the table of content
The document is archived and information here might be outdated

Recommendations for Choosing Between Functions and Macros

Most Microsoft run-time library routines are compiled or assembled functions, but some routines are implemented as macros. When a header file declares both a function and a macro version of a routine, the macro definition takes precedence, because it always appears after the function declaration. When you invoke a routine that is implemented as both a function and a macro, you can force the compiler to use the function version in two ways:

  • Enclose the routine name in parentheses.
    #include <ctype.h>
    a = toupper(a);    //use macro version of toupper
    a = (toupper)(a);  //force compiler to use function version of toupper
  • "Undefine" the macro definition with the #undef directive:
    #include <ctype.h>
    #undef toupper

If you need to choose between a function and a macro implementation of a library routine, consider the following trade-offs:

  • Speed versus size. The main benefit of using macros is faster execution time. During preprocessing, a macro is expanded (replaced by its definition) inline each time it is used. A function definition occurs only once regardless of how many times it is called. Macros may increase code size but do not have the overhead associated with function calls.
  • Function evaluation. A function evaluates to an address; a macro does not. Thus you cannot use a macro name in contexts requiring a pointer. For instance, you can declare a pointer to a function, but not a pointer to a macro.
  • Macro side effects. A macro may treat arguments incorrectly when the macro evaluates its arguments more than once. For instance, the toupper macro is defined as:
    #define toupper(c) ( (islower(c)) ? _toupper(c) :  (c) )

    In the following example, the toupper macro produces a side effect:

    #include <ctype.h>
    int a = 'm';
    a = toupper(a++);

    The example code increments a when passing it to toupper. The macro evaluates the argument a++ twice, once to check case and again for the result, therefore increasing a by 2 instead of 1. As a result, the value operated on by islower differs from the value operated on by toupper.

  • Type-checking. When you declare a function, the compiler can check the argument types. Because you cannot declare a macro, the compiler cannot check macro argument types, although it can check the number of arguments you pass to a macro.

See Also

C Run-Time Libraries

© 2016 Microsoft