liveBook · Manning

Type-generic macro

As explained in Modern C, Third Edition

A type-generic statement is a statement-form macro expansion whose operations can adapt to the types of its arguments or associated objects.

A type-generic statement macro expands to statements rather than an expression: it performs an operation without producing a value. Unlike an expression macro that relies on arithmetic conversions, it can use types supplied as macro arguments to declare suitable local variables. section 18.1.3

 #define dataCondStore(T, BASE, P, E, D)      \
   do {                                       \
     T* _pr_p = (P);                          \
     BASE _pr_expected = (E);                 \
     BASE _pr_desired = (D);                  \
     bool _pr_c;                              \
     do {                                     \
       mtx_lock(&_pr_p->mtx);                 \
       _pr_c = (_pr_p->data == _pr_expected); \
       if (_pr_c) _pr_p->data = _pr_desired;  \
       mtx_unlock(&_pr_p->mtx);               \
     }  while(!_pr_c);                        \
   } while (false)

The dataCondStore listing is a statement-form example. Its T and BASE parameters supply the pointer and value types; P, E, and D are captured in local variables before the locking loop. section 18.1.3

Two details make the expansion usable at a call site:

  • The outer do ... while(false) lets the invocation behave syntactically like a void function call, including its trailing semicolon. section 18.1.3
  • Local variables evaluate each macro argument at most once. The inner loop then locks the mutex, compares data with the expected value, conditionally assigns the desired value, and unlocks. section 18.1.3

TAKEAWAY: Grouping statements in a macro can provide a type-adaptable, void-like interface, but proper coding involves a tradeoff in ugliness and maintenance. Do not confuse this pattern with <tgmath.h> macros or _Generic-based dispatch, which select type-appropriate functions for expression calls. section 18.1.3 section 18.2

How Modern C, Third Edition covers it

How deep it goes
Works through a locking macro’s wrapper, typed local variables, single argument evaluation, and loop, while acknowledging maintenance costs.
Examples
Uses a dataCondStore macro with typed temporaries, mutex locking, comparison, conditional assignment, and an outer do ... while(false).
What it assumes
Assumes familiarity with C structures, assignments, and mutex operations while explaining the relevant preprocessor-macro technique.
What you can do after
Build it from scratch using a do ... while(false) wrapper and typed temporaries that evaluate macro arguments at most once.
How it connects
Connects preprocessor macros to arithmetic conversions, mutexes, and generic selection as distinct routes to type-generic programming.

Also explained in

Compare how 2 books explain type-generic macro →

Related concepts

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