Macro in C

A macro in C is a named piece of replacement text created with the #define directive. When the preprocessor sees that macro name, it replaces it with the defined text before compilation. This means macros are not functions and not variables. They are preprocessor-level substitutions that happen earlier than compilation.

Macros are extremely common in C programming because they can define symbolic constants, create small reusable code patterns, support conditional compilation, and build compiler-friendly abstractions. But they also need care, because macros do not follow function rules, type checking, or runtime semantics. In this article, we will understand macro in C, its syntax, types, common examples, pitfalls, and best practices.

What is Macro in C?

A macro in C is a preprocessor definition created using #define. It tells the preprocessor to replace a name with some other text before the compiler processes the code.

In simple words, a macro is a text substitution rule, not a runtime feature.

A macro expands before compilation. A function runs after compilation.

Syntax of Macro in C

The basic syntax is:

#define MACRO_NAME replacement_text

Example:

#define PI 3.14159

Whenever the preprocessor sees PI, it replaces it with 3.14159.

How Macro Works in C

  1. You define a macro with #define.
  2. The preprocessor scans the source file.
  3. Every matching macro name is replaced with its definition.
  4. The compiler then compiles the expanded code.

This means the compiler does not see the macro name in its original form. It usually sees only the expanded result.

Types of Macros in C

Macro typeDescription
Object-like macroReplaces a name with a constant or text value
Function-like macroLooks like a function call and accepts arguments
Multi-line macroExpands into multiple statements
Special macroUses operators like # or ##

Object-Like Macro in C

An object-like macro is the simplest kind. It usually behaves like a named constant.

#define MAX_SIZE 100
#define PI 3.14159

These are commonly used for sizes, flags, numeric constants, and compile-time configuration values.

Function-Like Macro in C

A function-like macro accepts parameters and expands using those arguments.

#define SQUARE(x) ((x) * (x))

When used like SQUARE(5), the preprocessor replaces it with ((5) * (5)).

Macros like this can be fast and convenient, but they are also a major source of bugs if written carelessly.

Why Parentheses Matter in Macros

Macro parameters should almost always be wrapped in parentheses, and the full expansion should usually be wrapped too. Otherwise operator precedence can change the meaning.

Unsafe macroSafer macro
#define SQUARE(x) x * x#define SQUARE(x) ((x) * (x))

Without parentheses, an expression such as SQUARE(a + b) expands incorrectly.

#define BAD_SQUARE(x) x * x
#define GOOD_SQUARE(x) ((x) * (x))

Example of Macro in C

The following example shows both a constant-style macro and a function-like macro.

#include <stdio.h>

#define PI 3.14159
#define AREA(r) (PI * (r) * (r))

int main(void)
{
    float radius = 5.0f;
    printf("%.2f\n", AREA(radius));
    return 0;
}

Here, the preprocessor expands AREA(radius) before the compiler handles the code.

Macro vs Function in C

PointMacroFunction
Handled byPreprocessorCompiler and runtime call mechanism
Type checkingNo normal function-type checkingYes
ExecutionText substitution before compilationRuns at program execution time
DebuggingOften harderUsually easier
Side effects riskHigherLower in normal use

Macros can be useful, but many tasks are clearer and safer with normal functions or const variables.

Macro vs const in C

For named constants, beginners often ask whether to use a macro or const.

Use caseUsually better choice
Simple typed numeric constantconst
Compile-time symbolic replacementMacro
Text substitution needed before compilationMacro
Readable typed value inside C logicconst

If type safety and debugger visibility matter more, const is often the better choice.

Multi-Line Macro in C

A macro can span multiple lines using the backslash continuation character.

#define PRINT_SUM(a, b) \
    do { \
        printf("%d\n", (a) + (b)); \
    } while (0)

The do { ... } while (0) pattern is commonly used so the macro behaves more safely like a single statement.

Stringizing Operator in Macro

The # operator inside a macro converts an argument into a string literal.

#define STRINGIFY(x) #x

This is useful in logging, debug messages, and generated text.

Token Pasting Operator in Macro

The ## operator joins two tokens together during macro expansion.

#define MAKE_VAR(a, b) a##b

This operator is useful in generated identifiers and certain low-level patterns, but it should be used carefully to keep code readable.

Common Problems with Macros in C

  • operator precedence bugs
  • multiple evaluation of arguments
  • harder debugging
  • lack of type checking
  • unreadable expansions in large codebases

One especially important problem is side effects.

#define DOUBLE(x) ((x) + (x))

If used as DOUBLE(i++), the expression may increment i more than once because the macro argument appears multiple times after expansion.

MistakeProblemSafer idea
No parenthesesWrong expression resultWrap parameters and whole expression
Repeated parameter useSide effects may happen multiple timesAvoid unsafe argument patterns
Overusing macrosReadability and debugging sufferPrefer functions or const when suitable
Multi-statement macro without wrapperCan break control flowUse do { ... } while (0)

Best Practices for Macro in C

  • Use parentheses carefully in function-like macros.
  • Prefer const or functions when they make code clearer.
  • Keep macros short, focused, and readable.
  • Use multi-line macros carefully with the standard wrapper pattern.
  • Avoid macros with hidden side effects.

FAQs

What is macro in C?

A macro in C is a preprocessor definition created with #define that replaces a name with some other text before compilation.

Are macros in C the same as functions?

No. Macros are text substitutions handled by the preprocessor, while functions are compiled program units that run at execution time.

Why are parentheses important in macros?

They prevent precedence bugs and help the expanded macro behave as intended inside larger expressions.

What is the difference between macro and const in C?

A macro is replaced before compilation, while const creates a typed value handled by the compiler.

What does ## mean in C macros?

The ## operator pastes two tokens together during macro expansion.

What does # mean in C macros?

The # operator converts a macro argument into a string literal. This is called stringizing.