The Magnificent World of Macros in C/C++

Götz von Berlichingen
3 min readMar 21, 2024

--

Macros! Those magnificent preprocessor directives that adorn C and C++ with their presence. To the uninitiated, macros are like those overly confident friends who insist they know a shortcut, only to lead you into a maze. They sweet-talk their way into your code, promising simplicity and speed, only to leave behind a labyrinth of confusion and regret. Let’s take a stroll down memory lane to appreciate why macros are, undoubtedly, the pinnacle of programming elegance.

Macros: The Epitome of Readability

Feast your eyes on this classic macro:

#define SQUARE(x) (x * x)

At first glance, it’s simplicity incarnate. Why bother with a function when you can achieve the same with less typing? But then, you use it in an expression that’s the epitome of reasonableness:

int a = 5, result;
result = 100 / SQUARE(a);

One might naively expect `100 / 25 = 4`, but surprise! Macro Land gifts us with `100`, because, naturally, `100 / 5 * 5` was our heartfelt desire. Macros possess that unique charm, gently reminding us about the joys of operator precedence.

Who Needs Type Safety Anyway?

The beauty of macros lies in their free spirit. Functions are such sticklers for details, always fussing over argument types. Macros, on the other hand, embody the true spirit of freedom. Observe:

#define MAX(a, b) ((a) > (b) ? (a) : (b))

The elegance! Who cares if `a` and `b` are integers, floating-point numbers, or — dare we say — pointers? But oh, the fun begins when you dare to mix types or, even better, use this macro in an intricate expression with side effects.

int x = 5;
double y = 6.5;
auto z = MAX(x++, y++);

Here’s to mixing types in ways that make compilers sob softly into their documentation, while also sneaking in those exhilarating bugs because `x` and `y` might get evaluated more than once. Who said programming had to be predictable?

Debugging: A Thrilling Hide and Seek Game

Picture yourself, debugger in hand, diving deep into the abyss of your code to unearth why your application decided to throw a tantrum. And there it is, a multi-line macro, a masterpiece of obscurity, designed to be as impenetrable as possible. Because clarity is overrated, right?

#define DO_THE_THING(x, y) {\
auto temp = someFunction(x);\
anotherFunction(temp, y);\
yetAnotherFunction(temp);\
}

Trying to step into that macro? Oh, but you can’t, for the debugger is blissfully unaware of the treasure hunt you’re on, thinking you’re still lounging on the same line. Isn’t it delightful when the very tools meant to aid you gaze upon your struggle with indifference?

Conclusion: Macros, A Testament to Programming Masochism

In closing, macros are not just a feature; they’re a rite of passage. They offer an unrivaled blend of exhilaration, bewilderment, and sheer panic, unmatched by any other language feature.

So, next time you feel the urge to use a macro for something that could be elegantly handled by a function, template, or constexpr, remember: just because you can, doesn’t mean you should. But then again, where would be the thrill in making sensible choices?

--

--

Götz von Berlichingen
Götz von Berlichingen

Written by Götz von Berlichingen

Software developer, former civil engineer. Musician. Free thinker. Writer.

Responses (3)