简体   繁体   中英

Multi-line macro defining another set of macros

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)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM