Why not to use macros (#define) in modern C++
Most of the people had changed their mobile phones classic nokia 3310 to a smartphones. Most of the people changes mobile phones every one or two year. Because newer phones have better performance, better feature, better technology then the older mobile phones.
Similar is with programming languages. Macros are legacy feature of “C” programming language which is carry forwarded to modern “C++” programming language.
I select an example of a classic ‘c’ language macros because Most of the projects which are converted to visual studio 6 to visual studio 2005 to visual studio 2017 to visual studio 2019 still uses macros. Even new code written still have macros.
What are disadvantages of using macros?
— > You cannot debug macros.
— >Macro do not have namespace so there are more chances for macro redefinition compiler warning
Most of the developer or reviewer came across a compiler warning C4005 which stands for macro redefinition.
Consider a situation where one developer has defined a macro viz.
namspace NAMESSPACE_A
{
#define SUCCESS 0
}.
Now a new developer started developing a code in which he require the same macro but do not know about the previously defined macro viz. SUCCESS, so he redefines a macro again in a different namespace
namspace NAMESSPACE_B
{
#define SUCCESS 1
}.
As we (C++ developers) know macros are preprocessor directives. Macros are replaced before the compilation process gets start. Compiler do not know about namespace when macros are being replaced by the compiler. So now in above example value of SUCCESS is changed to 1 i.e. last defined value of a macro in your code even though they are defined in different namespaces. This leads to an error as your old code is written considering value of SUCCESS as 0.
— >Macro can lead to strange side effects
Consider the macro #define SQUARE (number) ((number)*(number))
long nNumber= 4;
long nSquare = SQUARE(++nNumber);
This statement is evaluated into nSquare = ((5)*(6)) = 30;
So macro can lead to strange side effects
— >Different modules can have different value for same macro.
If we include a third party module in our code then it can have same macro name in the code, which leads to the erroneous result
Even Microsoft has released patches for macro redefinition warning, refer link given below
What should be the replacement for macros?
Macros are replaceable with enum class, const, inline, typedef, template and constexpr.
Even majority of static code analyzers give the warning/error stating that “Macros should not be used to define constant”
Refer below example taken from sonar source code analysis rule on how to replace macro with appropriate modern C++ language feature
Noncompliant Code Example
#define MAX_MEMORY 640 // Noncompliant#define LEFT 0 // Noncompliant
#define RIGHT 1 // Noncompliant
#define JUMP 2 // Noncompliant
#define SHOOT 3 // Noncompliant
Compliant Solution
constexpr size_t MAX_MEMORY = 640;
enum class Actions {Left, Right, Jump, Shoot};
Reference is also taken from C++ Core guidelines