Is there any methods to remove a line of code from a Release build, but leave it in the Debug build without ugly #if statements?
For example, is there some way to achieve the equivalent of the below code without using all these if statements?
#if DEBUG
Log.Log("I am in debug mode");
#endif
If I have a conditional, run-time check in the Log.Log function, then the string "I am in debug mode" will be preserved within my compiled executable, which is exactly what I do not want.
Define another macro in a common, shared header.
#ifdef DEBUG
#define LOG(m) Log.Log(m);
#else
#define LOG(m) do {} while(false);
#endif
Then replace your calls to Log.Log with LOG.
You'll ultimately need a preprocessor conditional somewhere, but you could apply it "upstream" in some shared header if you want to keep your application code clean. In that case, you'd have something like
#if DEBUG
#define DebugLog(m) Log.Log(m);
#else
#define DebugLog(m)
#endif
in the header associated with Log, and instead of calling Log.Log(m) inside a preprocessor conditional in your application code, you'd just call DebugLog(m). In a Debug build, the macro would expand to Log.Log(m), but otherwise it would just disappear entirely.
Have your Log.Log function #ifdef'd based on the build. So in DEBUG, it logs stuff, and in RELEASE, it's a no-op. For example:
namespace Log
{
void Log()
{
#if DEBUG
//Insert logging code here.
#endif
}
}
Related
I am creating c++ library modules in my application. To do logging, I use spdlog. But in a production environment, I don't want my lib modules to do any logging. One way to achieve turning on/off would be to litter my code with #ifdef conditionals like...
#ifdef logging
// call the logger here.
#endif
I am looking for a way to avoid writing these conditionals. May be a wrapper function that does the #ifdef checking and write it. But the problem with this approach is that I have to write wrappers for every logging method (such as info, trace, warn, error, ...)
Is there a better way?
You can disable logging with set_level():
auto my_logger = spdlog::basic_logger_mt("basic_logger", "logs/basic.txt");
#if defined(PRODUCTION)
my_logger->set_level(spdlog::level::off);
#else
my_logger->set_level(spdlog::level::trace);
#endif
spdlog::register_logger(my_logger);
You can disable all logging before you compile the code by adding the following macro (before including spdlog.h):
#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_OFF
#include<spdlog.h>
It is explained as a comment in the file https://github.com/gabime/spdlog/blob/v1.x/include/spdlog/spdlog.h :
//
// enable/disable log calls at compile time according to global level.
//
// define SPDLOG_ACTIVE_LEVEL to one of those (before including spdlog.h):
// SPDLOG_LEVEL_TRACE,
// SPDLOG_LEVEL_DEBUG,
// SPDLOG_LEVEL_INFO,
// SPDLOG_LEVEL_WARN,
// SPDLOG_LEVEL_ERROR,
// SPDLOG_LEVEL_CRITICAL,
// SPDLOG_LEVEL_OFF
//
Using this macro will also speed up your productive code because the logging calls are completely erased from your code. Therefore this approach may be better than using my_logger->set_level(spdlog::level::off);
However, in order for the complete code removal to work you need to use either of the macros when logging:
SPDLOG_LOGGER_###(logger, ...)
SPDLOG_###(...)
where ### is one of TRACE, DEBUG, INFO, WARN, ERROR, CRITICAL.
The latter macro uses the default logger spdlog::default_logger_raw(), the former can be used with your custom loggers. The variadic arguments ... stand for the regular arguments to your logging invocation: the fmt string, followed by some values to splice into the message.
I don't know spdlog.
However, you may define a macro in one of your common used include file, to replace the logcall by nothing, or a call to an empty inline function which the compiler optimizer will eliminate.
in "app.h"
#ifndef LOG
#ifdef logging
#define LOG spdlog
#endif
#ifndef logging
#define LOG noop
#endif
#endif
Did you get the idea?
This let most of your code untouched
According to cplusplus.com, the syntax to define a macro is:
#define identifier replacement
However, I sometimes stumble upon a macro definition which doesn't contain a replacement. For example in afxwin.h, there is the following preprocessor definition:
#define afx_msg // intentional placeholder
My questions:
What happens at compile-time when a preprocessor definition that doesn't have a replacement is used? Is it simply ignored? For example, does the line afx_msg void OnAddButton(); become void OnAddButton();?
What is the purpose of using preprocessor without replacement? Is it simply to make code more clear?
"Nothing" (no text) is a valid replacement text for a macro. It will simply be removed (more precisely, replaced by nothing) by the preprocessor.
There are multiple reasons why you'd use something like this. One is to simply use the macro in #ifdef and similar constructrs.
Another is conditional compilation. A typical use case is public APIs and DLL exports. On Windows, you need to mark a function as exported from a DLL (when building the DLL) or as imported from a DLL (when linking against the DLL). On ELF systems, no such declarations are necessary. Therefore, you'll often see code like this in public library headers:
#ifdef _WIN32
#ifdef BUILDING_MYLIB
#define MYLIB_API __declspec(dllexport)
#else
#define MYLIB_API __declspec(dllimport)
#endif
#else
#define MYLIB_API
#endif
void MYLIB_API myApiFunction();
Yet another reason could be code processing tools. Perhaps you have a tool which parses source code, extracting a list of functions with a certain marker. You can define such a marker as an empty macro.
#define bla
simply defines bla.
you can use it with
#ifdef bla
...
place some code here
...
#endif
a typical use case is #define DEBUG to enable special code parts in debugging mode.
Another way to set such things from "outside" is:
g++ -DDEBUG x.cpp
which also sets the macro DEBUG defined.
And every header file should have something like:
#ifndef THIS_HEADER_INCLUDE_GUARD
#define THIS_HEADER_INCLUDE_GUARD
...
rest of header file
...
#endif
This simply protects your header file for (recursivly) read more the once.
Some can be done with implementation specific #pragma once.
the preprocessor processes it, removing it and replacing it with nothing
could be a variety of reasons, including readability, portability, custom compiler features, etc.
I tried to use a library on visual studio in different ways by modify its macros on preprocessor directives. However a logic block inside an #if directive is shown to me inactive as it was comment. Here is the code:
#if defined EBML_DLL
#if defined EBML_DLL_EXPORT
#define EBML_DLL_API __declspec(dllexport)
#else // EBML_DLL_EXPORT
#define EBML_DLL_API __declspec(dllimport)
#endif // EBML_DLL_EXPORT
#else // EBML_DLL
#define EBML_DLL_API
#endif // EBML_DLL
The problems is that visual studio shows the code within if ebml_dll block inactive (as commented). As result, the dll doesn't show the functions in the object browser of VS.
A Hint: if a backslash is added at the end of #if defined EBML_DLL's line, it active the else block only.
There was a bug in older versions of VS about this, but it was just a display issue. VS was not reading the defines correctly (in your case EBML_DLL, etc).
It could also be that the constants you are using in your preprocessor statements are not correct and the are missing characters (usually the ones the compiler uses have underscores at the beginning and end)
To really know for sure which one it is, you can add a random string inside the branch the preprocessor is expected to take and see if the code compiles.
#if defined EBML_DLL
this_should_not_compile //you should get an error on this line
#endif
Hope this helps...
Suppose that I have 10,000 lines of C++ code. 200 lines of this code are for testing purpose (for example, check the program and show an error message).
Is there an way in C++ to ignore or consider some lines of the code (maybe with preprocessor keywords)?
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 to Project > Properties > C/C++ > Preprocessor > Preprocessor Definitions. Or,
For GCC, compile your code with option -DMY_CONTROL_MACRO.
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.
Go with the existing convention, and use the NDEBUG macro. All common compilers define this macro for release builds, and do not define it for debug builds.
The macro originally existed to control the output of assert(3), and is defined as such all the way back in the POSIX standard and at least since C89.
Note that you have to reverse the test with #ifndef.
An example:
#ifndef NDEBUG
/* Debugging code */
std::cerr << "So far we have seen " << unicorns << " unicorns" << std::endl;
#endif
P.S. With gcc/g++, you do a debug build by adding -g to the command line.
Surround your testing code #ifdef DEBUG.
#if DEBUG
....
#endif
The way to go is using preprocessor directive with the define passed to the compiler or taken from a header "config.h":
#if defined(DEBUG) // or #ifdef DEBUG
// Debug code
#endif
To avoid to use everywhere in source code:
#if defined(DEBUG)
My_Debug_function(some_variable)
#endif
You may do in the header
#if !defined(DEBUG) // or #ifndef DEBUG
# define My_Debug_function(some_variable) do { static_cast<void>(some_variable); } while (false) /* Do nothing */
#endif
And so use My_Debug_function almost normally.
Use preprocessor #define and #if
depending on your compiler, you should have some variables available by default i.e NDEBUG (for not-debug) or DEBUG
you can define a variable yourself in code by
#define MY_VARIABLE
and use it as follows
#ifdef MY_VARIABLE
//code that compiles only if MY_VARIABLE is defined
printf("test output here");
#else
//code that compiles only if MY_VARIABLE is NOT defined
printf("MY_VARIABLE is not defined");
#endif
for more information search online for
#define, #if, #ifdef, #ifndef
One normal procedure to implement debugging is the use of
#ifdef DEBUG
...debugging tests...
#endif
Sometimes, a typical "checking" algorithm is needed in some parts of the code, and so one would normally like to wrap it on a function, such that the code is only called when DEBUG flag is defined. Let that function be called myDebug();
I see two natural approaches for this: either ifdef is added on each time myDebug() is called, like this:
#ifdef DEBUG
myDebug();
#endif
Or myDebug is defined as:
void myDebug()
{
#ifdef DEBUG
...code...
#endif
}
Basically, the first avoids the function calling, while the second avoid putting the code with a lot of #ifdef/#endif.
Is there any "standard" convention to choose one of the two, or another way that I don't know? Is is worth to choose the second from the "styling" point of view?
Thanks
I'd go with number 3:
#ifdef DEBUG
#define myDebug(x) myDebug(x)
#else
#define myDebug(x) {}
#endif
This way, there's no pesky #ifdefs everywhere in the code, and for a non-debug build no code will be generated.