While most naming conflicts in C++ can be solved using namespaces), this is not true for preprocessor macros.

This post is outdated. You will find an updated version here:
How and Why to Avoid Preprocessor Macros

Macros can not be put into namespaces. If you would try to declare a new class called Stream, but somewhere in a header you include would be a macro called Stream, things would break. While compiling your code, the preprocessor would simply replace the Stream in your class Stream { declaration. You could get a really confusing error message, and it would take time and energy to find the actual problem.

Especially people developing software for controllers, often overuse macros for almost everything. They believe it will save RAM, speed up the code or make it more flexible. Often none of these three things are true. Actually each additional macro is a risk for name conflicts and makes the code less readable. You should reduce the use of macros to the absolute minimum, and especially avoid macros in your header files.

Avoid Macros for Constants

Many people are using macros for constants. They believe, because the macro will be expanded before the compiler will actually “see” the value, it will produce better code.

#define MY_CONSTANT 10

uint8_t doSomething()
{
  uint8_t x = 0;
  x += MY_CONSTANT;
  return x;
}

The produced Arduino sketch has 450 bytes, and uses 9 bytes of dynamic memory. And it will produce very simple assembler code for the function as shown below.

ldi r24,lo8(10)
ret

You can spot the 10 where the compiler inserted the constant. But let us compare the code if we use a constant variable. The compiler usually does not reserve memory for simple constant variables, except this will save time and space.

const uint8_t MY_CONSTANT = 10;

uint8_t doSomething()
{
  uint8_t x = 0;
  x += MY_CONSTANT;
  return x;
}

The produced Arduino sketch has 450 bytes, and uses 9 bytes of dynamic memory. Again! There is no difference in memory usage. But let us have a look at the produced assembler code:

ldi r24,lo8(10)
ret

There is absolutely no difference. But while there is no difference in the result, there is a difference in the code. You give the constant value a type, which allows the compiler to detect problems in your code. For example you define a signed integer as a constant, but use it in a unsigned context. This may lead to a problem, but you won’t detect this problem if you are using macros. With a declared constant, the compiler will at least give you a warning message.

Avoid Macros for Header Guards

A long time in the past, it was necessary to use macros to protect headers from included twice by the preprocessor and compiler. This looked like this:

#ifndef MYCLASS_H
#define MYCLASS_H

// your declarations.

#endif

Not only have you the risk of naming conflicts with the macros used for the guard, the compiler has no clue of your intentions and can therefore not optimize its behavior.

There is the #pragma once which is supported by all modern compilers which was made to prevent a header included twice in one compiling unit. The compilers implement this in a very safe and efficient way. It is speeding up the compile time, especially for large projects, and it avoids the risk of naming conflicts. If you do not have the need to support compilers which are 10 or more years old, please use code like this:

#pragma once

// your declarations.

Avoid Macros for “Flexibility”

You write a library, but you want to make it work with different controllers. Soon people start to declare macros and include lots of #ifdef, #else and #endif statements in the code. There are many disadvantages of this: The first is readability of your code. It is really hard to see which part of your code will actually be executed and which not. Another is missing compiler checks. Each part which is removed by the precompiled, is never compiled after all. If this part contains errors, you will never know until you “activate” this code part.

There is a simple alternative: Use C++ constants! Have a look at the following example code:

enum ControllerType {
  ControllerType_Uno,
  ControllerType_Due
};

const ControllerType CONTROLLER = ControllerType_Uno;

uint8_t doSomething()
{
  uint8_t x = 0;
  if (CONTROLLER == ControllerType_Uno) {
    x += 100;
  } else {
    x += 80;
  }
  return x;
}

The assembler code created for the function doSomething() is shown below. You can clearly see it only contains the constant 100 and the compiler removed the second part – because obviously it will never be used.

ldi r24,lo8(100)
ret

When to Use Macros

There are some situations where you can not avoid using macros. If you are using macros, you should try to follow this rules:

  • Use macros only in “cpp” files.This will limit the scope of the macros, which will help you find any conflicts. You actually just have to search in one file for it.
  • Add a unique prefix to the name and only use uppercase letters.A unique prefix in front of each macro reduces the risk of naming conflicts. At least you should prefix them with the name of your project, library or class. Better would be an unique identifier equal to your namespace (but uppercase).
  • Use them only if a C++ constant does not work.This is always the case if the produced code does not equal code which can be generated using macros.

Looking at code for e.g. the Arduino platform, there are a few uses for preprocessor macros:

  • Removing debugging code from the library.The C++ constants usually do not work here, because strings constants are kept, even they are not actually used. I am puzzled why, because there is an option to remove unused string literals, which is not set.
  • Make accessing ports flexible.Actually you could use a pointer to uint8_t, but I would not bet on it. So here it is probably better to use a macro to insert the special volatile address into your code

See also: How and Why to Use Namespaces