DEV Community

Cover image for Code Smell 56 - Preprocessors
Maxi Contieri
Maxi Contieri

Posted on • Updated on • Originally published at

Code Smell 56 - Preprocessors

We want our code to behave different on different environments, operating systems, so taking decisions at compile time is the best decision, isn't it?.


  • Readability

  • Premature Optimization

  • Unnecessary complexity

  • Debugging


  1. Remove all compiler directives.

  2. If you want different behavior, model it with objects

  3. If you think there's a performance penalty, make a serious benchmark instead of doing premature optimization.

Sample Code


#if VERBOSE >= 2
  printf("trace message");
Enter fullscreen mode Exit fullscreen mode


if (runtimeEnvironment->traceDebug()) {
  printf("trace message");

## even better with polymorphism and we avoid annoying ifs

runtimeEnvironment->traceDebug("trace message");

Enter fullscreen mode Exit fullscreen mode


This is a syntactic directive promoted by several languages, therefore it is easy to detect and replace with real behavior.


  • Compilers

  • Metaprogramming


Adding an extra layer of complexity makes debugging very difficult. This technique was used when memory and CPU were scarce. Nowadays, we need clean code and we must leave premature optimization buried in the past.

Bjarne Stroustrup, in his book The Design and Evolution of C++, regrets on the pre-processor directives he created years before.


More info


C Preprocessor

#ifdef Considered Harmful


Photo by CDC on Unsplash

C++ is designed to allow you to express ideas, but if you don't have ideas or don't have any clue about how to express them, C++ doesn't offer much help.

Bjarne Stroustrup

This article is part of the CodeSmell Series.

Top comments (5)

netch80 profile image
Valentin Nechayev

runtimeEnvironment->traceDebug("trace message");

Maybe the best variant is when the use calls look that simple, but, at compiler level, they are instantiated with real code or with stubs, depended on compiler directives. So all these #if are concentrated in declaration source. In a project, we used this in a variant with two level axes, so, for example, DEBUG_MIN is compiled always (with runtime check) but DEBUG_MAX if log set is >=MAX during compilation.

For regrets on preprocessor, the main problem with it is not preprocessing itself - but its low level (just textual replacement). Common LISP is fundamentally based on preprocessor but it is really high-level, with content analyzer. If an analog was added to C++, most of template magic wouldn't be needed.

winstonpuckett profile image
Winston Puckett

I totally agree with the concept. One question, it looks like the wrong and right samples are the same, is that right?

mcsee profile image
Maxi Contieri

Uhh. Something in cache on the app happens.

I have reported this to them since it happens in all my smells.

Try refreshing the article

darkwiiplayer profile image
𒎏Wii 🏳️‍⚧️

This technique was used when memory and CPU were scarce.

Memory and CPU will always be finite.

mcsee profile image
Maxi Contieri

of course. but nowadays we are more concerned on writing declarative, less coupled and evolutionary software than making optimization hacks.

We don't need to waste resources. And software maintenance and evolution is our most scare resource now.