Preprocessor Definitions
Preprocessor definitions are a tool in C. It is important to know how and when to use them, as well as the implications they have. Note that C++ has many tools such as inline functions that may be better suited compared to a preprocessor definition such as a macro.
Macros
A macro is implemented by using
#define
. Put simply, a macro will quite literally replace any text of your choosing with another piece of text. Consider the following code snippet:#define TWO (2) #define ARRAY_SIZE(a) (sizeof(a)/sizeof(*a)) //stuff in between static uint16_t test_array[] = {1,2,3}; int main() { uint8_t something = TWO + TWO; uint8_t array_size = ARRAY_SIZE(test_array); }
will evaluate to
#define TWO (2) #define ARRAY_SIZE(a) (sizeof(a)/sizeof(*a)) //stuff in between static uint16_t test_array[] = {1,2,3}; int main() { uint8_t something = (2) + (2); uint8_t array_size = (sizeof(test_array)/(sizeof(*test_array)); }
It simply replaces everything that was defined with your new term (i.e. TWO quite literally evaluated to (2)).
A macro can be quite useful in the case of ARRAY_SIZE, where you do not have to know what type of pointer something is to use it.
IMPLEMENTATION NOTES
Always put brackets around macros, as not doing so can result in weird things happening if the user forgets a bracket etc.
The convention is to make macros in ALL CAPS.
However, using a macro may have significant drawbacks
Nothing you type in a macro is ‘safe’, and everything is directly swapped out for what you defined. A simple typo can cause an error.
You also cannot step through a macro with a debugger.
Further reading on a debugger: The Debugger
Other preprocessor definitions
#ifdef and #ifndef are quite popular, you can use this to toggle features or do whatever really. Consider the following code snippet
//features.h #define MY_FEATURE //main.c int main() { #ifdef MY_FEATURE //Do something #else //Do something else #endif }
Beware for those who intend to do work in the automotive industry, I believe MISRA C does not permit this design pattern in released code. Still really good for debugging etc, since you can just do
#define DEBUG
and#ifdef DEBUG
to make your code much cleaner instead of removing and adding comments
#error is good to provide compile-time errors. Further reading on #error can be found here: https://www.techonthenet.com/c_language/directives/error.php