liveBook · Manning

Function-like macro

As explained in Modern C

A function-like macro is a C macro defined with parameters that expands preprocessing tokens when invoked with an argument list resembling a function call.

A call-shaped replacement

`#define putchar(A) putc(A, stdout)` gives `putchar` a parameter, `A`, and replacement text that passes it to `putc`. A use looks like a function call, but the preprocessor replaces it with text before compilation. section 8.1.2

A function-like macro is defined with a parameter list after its name and is invoked with a parenthesized argument list. During preprocessing, commas outside nested parentheses separate arguments. Arguments are expanded, substituted for parameters in a copy of the replacement text, and the result is scanned for further macro replacements. The macro being expanded is temporarily disabled to prevent infinite recursion. section 16.1

A repeated argument is not one evaluation

Consider `#define square_macro(X) (X*X)`. Substituting `count()` for `X` produces `count()*count()`: the side-effecting function is called twice. By contrast, an inline function taking one unsigned parameter receives the result of one `count()` call. TAKEAWAY: Prefer an inline function when the number and types of arguments are known. section 16.0

If a macro is needed, make its call-like appearance trustworthy:

  • Parenthesize parameters and the whole replacement expression. Without an outer pair, a macro replacing `sum(5, 2)*7` with `5+2*7` does not group the sum as intended. section 10.2.1
  • Avoid repeating an argument that might have side effects; a replacement can evaluate it more than once. section 10.2.1
  • Keep control flow visible and make statement-like uses fit their surrounding syntax. A `do { ... } while (false)` wrapper can prevent an `else` from attaching to an `if` hidden inside a macro. section 10.2.1

Macros remain useful when a function interface cannot express a requirement. Surrounding an argument with string literals in a replacement can require a literal rather than a character array; a tracing macro uses this to constrain its format argument. Other uses include default arguments, variable argument lists, and type-generic interfaces combined with `_Generic`. section 16.2 section 16.7

How Modern C covers it

How deep it goes
Works through argument separation, expansion, substitution, and rescanning, then examines evaluation and syntax hazards.
Examples
Contrasts a squaring macro with an inline function and uses a dangling-else repair and string-literal checking to expose practical constraints.
What it assumes
Assumes familiarity with expressions, function calls, and side effects; explains preprocessing replacement explicitly.
What you can do after
Build it from scratch when needed, while choosing inline functions for ordinary typed calls and checking expansion for duplicated effects or surprising syntax.
How it connects
Connects preprocessing to inline functions, side effects, string literals, variadic interfaces, and `_Generic`.

Also explained in

Compare how 3 books explain function-like macro →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Modern C. The section links point to the parts of the book it draws on.