Force the compiler to ignore some lines in the program
Short answer:
Use macros and #ifdef
checking. For example:
#ifdef MY_CONTROL_MACRO
...
#endif
the code within this scope will only be compiled if you already defined the MY_CONTROL_MACRO
macro.
More stuff:
-
To define such a macro, you can
- Add
#define MY_CONTROL_MACRO
to your code. Or, - For VS, add
MY_CONTROL_MACRO
toProject > Properties > C/C++ > Preprocessor > Preprocessor Definitions
. Or, - For GCC, compile your code with option
-DMY_CONTROL_MACRO
.
- Add
-
You can check out here for more info.
This block is called a conditional group. controlled text will be included in the output of the preprocessor if and only if MACRO is defined. We say that the conditional succeeds if MACRO is defined, fails if it is not.
The controlled text inside of a conditional can include preprocessing directives. They are executed only if the conditional succeeds. You can nest conditional groups inside other conditional groups, but they must be completely nested. In other words, ‘#endif’ always matches the nearest ‘#ifdef’ (or ‘#ifndef’, or ‘#if’). Also, you cannot start a conditional group in one file and end it in another.
-
You can also use the advanced
ifdef-else-endif
style:#ifdef MY_CONTROL_MACRO ... // this part will be valid if MY_CONTROL_MACRO is defined #else ... // this part will be valid if MY_CONTROL_MACRO is NOT defined #endif
Surround the code with "#ifdef...#endif", and then use the compiler options to set the flag:
#ifdef MYTEST_ONLY_FUNCTIONALITY_ENABLED
...
#endif
You can then use the compiler options to include this code. For example, in GCC:
-DMYTEST_ONLY_FUNCTIONALITY_ENABLED
Though, to be honest, I think this approach is generally not very maintainable in large projects and, if possible, it is generally better to simply move the test-only code to a completely separate library (without this conditional logic) and simply link that code into your test binary rather than your non-test binary. That also avoids having to compile each of the other libraries in both debug and non-debug modes.
This is what #ifdef
was designed for
You put
#ifdef TESTS
... test code ...
#endif
and then you can pass to the compiler options to decide if you want the test part compiled in or not. For example with g++ it's
g++ -DTESTS ...
Using a preprocessor guard is definitely the most flexible and common approach. However, when possible, I suggest using an if statement. For example, instead of
void example(int a){
int some_local;
...
#ifdef _DEBUG
std::cout << "In function " << __FUNCTION__ << "(" << a <<")" << std::endl;
#endif
....
}
Assuming ENABLE_DEBUG is defined to be 0 or non-zero, I would use
void example(int a){
int some_local;
...
if(ENABLE_DEBUG) std::cout << "In function " << __FUNCTION__ << "(" << a <<")" << std::endl;
...
}
Since ENABLE_DEBUG is a constant, when ENABLE_DEBUG is 0 the compiler will not generate any code for statements it guards. So, why use this method instead of #ifdef?
- If there are many separate debug statements spread throughout the code, it can be a bit easier to read
- More importantly, the code is always processed for syntactic errors, even if no code is generated. This can be very helpful if the debug code is not frequently enabled. If variables change (e.g. in the above example if the argument a was renamed), then the person making the change will know they have to update the debug statement as well. If #ifdefs are used, then it can hide bit rot until someone needs to enable the debug code and then they have to go and try and fix up the code, something that may not be obvious to them.
Obviously this approach only works for debug statements inside method/function bodies.