In my project I have very many files and I want to manage debug with C++ macros. For every file, I want to use its own switch for enable or disable debug and adjust debug level. So basically there is shared file with settings:
This is how shared file debug.h looks:
#define DEBUG_LEVEL_LOG -1
#define DEBUG_LEVEL_NONE 0
#define DEBUG_LEVEL_ERROR 1
#define DEBUG_LEVEL_WARNING 2
#define DEBUG_LEVEL_INFO 3
#define DEBUG_LEVEL_DEBUG 4
#define DEBUG_LEVEL_TRACE 5
#ifndef ON
#define ON 1
#endif
#ifndef OFF
#define OFF 0
#endif
// setings for component "wireless"
#define WIRELESS_DEBUGGING ON
#define WIRELESS_DEBUGGING_LEVEL DEBUG_LEVEL_ERROR
// settings for another components
...
In every file I want to debug with this settings I need to define another bunch of macros. For example file "wireless.h"
#ifndef WIRELESS_DEBUGGING
#define WIRELESS_DEBUGGING_LEVEL DEBUG_LEVEL_NONE
#endif
#if WIRELESS_DEBUGGING
#if WIRELESS_DEBUGGING_LEVEL >= DEBUG_LEVEL_LOG
#define WIRELESS_LOG(...); Logger::log(__VA_ARGS__);
#else
#define WIRELESS_LOG(...); {}
#endif
#if WIRELESS_DEBUGGING_LEVEL >= DEBUG_LEVEL_ERROR
#define WIRELESS_ERROR(...); Logger::error(__VA_ARGS__);
#else
#define WIRELESS_ERROR(...); {}
#endif
#if WIRELESS_DEBUGGING_LEVEL >= DEBUG_LEVEL_WARNING
#define WIRELESS_WARNING(...); Logger::warning(__VA_ARGS__);
#else
#define WIRELESS_WARNING(...); {}
#endif
#if WIRELESS_DEBUGGING_LEVEL >= DEBUG_LEVEL_INFO
#define WIRELESS_INFO(...); Logger::info(__VA_ARGS__);
#else
#define WIRELESS_INFO(...); {}
#endif
#if WIRELESS_DEBUGGING_LEVEL >= DEBUG_LEVEL_DEBUG
#define WIRELESS_DEBUG(...); Logger::debug(__VA_ARGS__);
#else
#define WIRELESS_DEBUG(...); {}
#endif
#if WIRELESS_DEBUGGING_LEVEL >= DEBUG_LEVEL_TRACE
#define WIRELESS_TRACE(...); Logger::trace(__VA_ARGS__);
#else
#define WIRELESS_TRACE(...); {}
#endif
#else
#define WIRELESS_LOG(...); {}
#define WIRELESS_ERROR(...); {}
#define WIRELESS_WARNING(...); {}
#define WIRELESS_INFO(...); {}
#define WIRELESS_DEBUG(...); {}
#define WIRELESS_TRACE(...); {}
#endif
When I want to debug given component, I simply use something like this (in wireless.cpp)
WIRELESS_TRACE("wireless: hello world\n");
... etc ...
So far it's working. And here is the question: I don't want to use "local" bunch of definitions similar to definitions in file "wireless.h" in every component I'm using only with different prefix. Instead of this I want to have some "super macro" which will look similar to this
REGISTER_DEBUG(WIRELESS);
Is there a way how to achieve this using some concatenation and multi-line macro? I have found that using #define inside #define is forbidden.
I'm not completely sure what you want, so if this doesn't fit let me know and I'll delete.
There is the possibility of concatenating tokens in the preprocessor using ##. See, for example, https://gcc.gnu.org/onlinedocs/cpp/Concatenation.html
This is somewhat clumsy, but should do the trick:
#define DEBUG_LEVEL_LOG -1
#define DEBUG_LEVEL_NONE 0
#define DEBUG_LEVEL_ERROR 1
#define DEBUG_LEVEL_WARNING 2
#define DEBUG_LEVEL_INFO 3
#define DEBUG_LEVEL_DEBUG 4
#define DEBUG_LEVEL_TRACE 5
#define TRACE(a,...) _TRACE(a,__VA_ARGS__)
#define _TRACE(a,...) __TRACE_##a(__VA_ARGS__)
#define __TRACE_5(...) do{Logger::trace(__VA_ARGS__);}while(0)
Here is the clumsiness: you also need to define __TRACE_4, __TRACE_3 and so on to be empty. And then you need to define the same thing for Debug:
#define __DEBUG_4(...) do{Logger::debug(__VA_ARGS__);}while(0)
But in the end, after you defined your Wireless log level:
#define WIRELESS_LEVEL 5
you can just call the macro just like this:
TRACE(WIRELESS_LEVEL,"wireless: hello world\n");
Edit
Alternatively (this might be cleaner):
#define __PRINT_55(...) do{Logger::trace(__VA_ARGS__);}while(0)
#define __PRINT_44(...) do{Logger::debug(__VA_ARGS__);}while(0)
// etc...
// Also need to define what you need to be not printed:
#define __PRINT_01(...)
// etc...
#define PRINT(a,b,...) _PRINT(a,b,__VA_ARGS__)
#define _PRINT(a,b,...) __PRINT_##a##b(__VA_ARGS__)
Now you can call your function like this:
PRINT(DEBUG_LEVEL_TRACE, WIRELESS_LEVEL, "Hello world\n");
You can get there by switching from macros to inline functions. Something like this:
// debug.h
enum DebugLevel {
DEBUG_LEVEL_LOG = -1,
DEBUG_LEVEL_NONE = 0,
DEBUG_LEVEL_ERROR = 1,
DEBUG_LEVEL_WARNING = 2,
DEBUG_LEVEL_INFO = 3,
DEBUG_LEVEL_DEBUG = 4,
DEBUG_LEVEL_TRACE = 5
};
// settings for component "wireless"
constexpr bool WIRELESS_DEBUGGING = true;
constexpr DebugLevel WIRELESS_DEBUGGING_LEVEL = DEBUG_LEVEL_ERROR;
#define REGISTER_DEBUG_FUNC(topic, level, func) \
template <typename... Args> \
inline void topic##_##level(Args&& ... args) { \
if ( topic##_DEBUGGING && topic##_DEBUGGING_LEVEL >= DEBUG_LEVEL_##level ) \
Logger::func(std::forward<Args>(args)...); \
}
#define REGISTER_DEBUG(topic) \
REGISTER_DEBUG_FUNC(topic, LOG, log) \
REGISTER_DEBUG_FUNC(topic, ERROR, error) \
REGISTER_DEBUG_FUNC(topic, WARNING, warning) \
REGISTER_DEBUG_FUNC(topic, INFO, info) \
REGISTER_DEBUG_FUNC(topic, DEBUG, debug) \
REGISTER_DEBUG_FUNC(topic, TRACE, trace)
// wireless.h
REGISTER_DEBUG(WIRELESS)
What is the difference between the C++ macro VERIFY() and ATLVERIFY() ? And which one is better to use for COM objects?
There is some difference in how the errors are reported. ATLVERIFY is defined as
#ifndef ATLVERIFY
#ifdef _DEBUG
#define ATLVERIFY(expr) ATLASSERT(expr)
#else
#define ATLVERIFY(expr) (expr)
#endif // DEBUG
#endif // ATLVERIFY
And ATLASSERT is
#ifndef ATLASSERT
#define ATLASSERT(expr) _ASSERTE(expr)
#endif // ATLASSERT
So it ends up in _ASSERTE (see https://msdn.microsoft.com/en-us/library/ezb1wyez.aspx )
While VERIFY is
#ifdef _DEBUG
#define VERIFY(f) ASSERT(f)
#else // _DEBUG
#define VERIFY(f) ((void)(f))
#endif // !_DEBUG
So it ends up in ASSERT (see https://msdn.microsoft.com/en-us/library/aa297139(v=vs.60).aspx )
I want to compile a project with a Makefile.
I have defined target for linux in one of my .h
#define LINUX_TARGET (COMPILER_GCC_4_4_1|FAMILY_LINUX|TYPE_X86)
...
#ifdef _LINUX_TARGET_
#define __linux__
#define TARGET LINUX_TARGET
...
#ifdef __linux__
#define __LINUX__
#endif
So in my Makefile I say that, I will use this target:
...
CFLAGS += -D_LINUX_TARGET_
...
Butwhen I compile i get this error :
../../../../../../../Generic/Common/Include/target_definition.h:145:0: warning: "__linux__" redefined [enabled by default]
#define __linux__
^
../../../RefFT/Float/src/LIMITOR_main_32f.c:1:0: note: this is the location of the previous definition
/*---------------------------------------------------------------------------
^
I don't understand why, beceause this works for macos or windows target...
EDIT
After Joachim Pileborg answer, what I did :
#define LINUX_TARGET (COMPILER_GCC_4_4_1|FAMILY_LINUX|TYPE_X86)
...
#ifdef _LINUX_TARGET_
#ifndef __linux__
#define __linux__
#endif
#define TARGET LINUX_TARGET
...
#ifdef __linux__
#define __LINUX__
#endif
Because __linux__ is pre-defined when building on Linux.
For example if I had this code:
#ifdef _DEBUG
mPluginsCfg = "plugins_d.cfg";
#else
mPluginsCfg = "plugins.cfg";
#endif
Can I define a macro that looks like
#define DEBUG_RELEASE(debug_code, release_code)
and then use it like this;
DEBUG_RELEASE(mPluginsCfg = "plugins_d.cfg";,mPluginsCfg = "plugins.cfg";)
I'm sure that it works, and I'm almost sure that it is defined to work.
#ifdef _DEBUG
#define DEBUG_RELEASE(d,r) d
#else
#define DEBUG_RELEASE(d,r) r
#endif
I'm unsure whether I've seen anything uglier in the wonderful world of preprocessor macros.
How should I write the below piece of code using macro function?
#ifdef LOG_ENABLED
m_logger->Log(szType,szMessage);
#endif
I have done something like mentioned below and it resulted in error:-
#define _LOG_MSG_CND_BEGIN_ #ifdef LOG_ENABLED
#define _LOG_MSG_CND_END_ #endif
#define WriteLogMessage(szType,szMessage) \
{\
_LOG_MSG_CND_BEGIN_\
m_logger->Log(szType,szMessage);\
_LOG_MSG_CND_END_\
}
Please let me know how to write macro function for the above three piece of code without any errors.
I have used inline function for the same piece of code but while debugging i saw that the inline function was not getting treated as inline function and so i want to use macro function in this case.
Inline function which i used was as mentioned below:-
inline void WriteLogMessage(LOG_LEVEL szType, LPCTSTR szMessage){
#ifdef LOG_ENABLED
m_logger->Log(szType,szMessage);
#endif
}
The standard C preprocessor is a bit of an idiot and doesn't understand much at all. You want something like this:
#if defined LOG_ENABLED
#define WriteLogMessage(szType,szMessage) m_logger->Log(szType,szMessage)
#else
#define WriteLogMessage(szType,szMessage)
#endif
Preprocessor directives need to be the first thing in a line:
#define _LOG_MSG_CND_BEGIN_
#ifdef LOG_ENABLED
#define _LOG_MSG_CND_END_
#endif
#define WriteLogMessage(szType,szMessage) \
{\
_LOG_MSG_CND_BEGIN_\
m_logger->Log(szType,szMessage);\
_LOG_MSG_CND_END_\
}
EDIT: If you want macros to be expanded to other macros, that's not possible.