2017-02-16 7 views
1

В моем проекте у меня очень много файлов, и я хочу управлять отладкой с помощью макросов C++. Для каждого файла я хочу использовать свой собственный переключатель для включения или отключения отладки и настройки уровня отладки. Таким образом, в основном есть общий файл с настройками:Многострочный макрос, определяющий другой набор макросов

Это как разделяемой файл debug.h выглядит:

#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 
... 

В каждом файле я хочу отладить с этой настройки мне нужно определить еще кучу макросов. Например, файл «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 

Когда я хочу отладить данный компонент, я просто использовать что-то вроде этого (в wireless.cpp)

WIRELESS_TRACE("wireless: hello world\n"); 
... etc ... 

До сих пор он работает. И вот вопрос: я не хочу использовать «локальную» группу определений, подобных определениям в файле «wireless.h», в каждом компоненте, который я использую только с другим префиксом. Вместо этого я хочу, чтобы иметь какой-то «супер-макро», который будет выглядеть примерно так

REGISTER_DEBUG(WIRELESS); 

Есть ли способ, как добиться этого с помощью некоторых конкатенации и многострочный макрос? Я обнаружил, что использование #define внутри #define запрещено.

+3

Лучше использовать сильную типизацию вещей (это то, что C++ в основном предлагает более C), и автоматизацию очистки с использованием RAII. Для отладки используйте хороший отладчик GUI, например, тот, что есть в Visual Studio.Короче говоря, хорошее профилактическое программирование и хорошие инструменты для случая, когда этого было недостаточно. –

+0

Сколько сообщений вы хотите контролировать во время компиляции и сколько вы хотите контролировать во время выполнения. Например, хотите ли вы передать аргумент «--debug-level = trace» и ожидать, что все сообщения «трассировки» будут напечатаны? –

ответ

0

Я не совсем уверен, чего вы хотите, поэтому, если это не подходит, дайте мне знать, и я удалю.

Существует возможность объединения токенов в препроцессор с использованием ##. Смотрите, например, https://gcc.gnu.org/onlinedocs/cpp/Concatenation.html

0

Это несколько неуклюжий, но должен сделать трюк:

#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) 

Вот неловкость: вам также необходимо определить __TRACE_4, __TRACE_3 и так далее, чтобы быть пустым. И тогда вам нужно определить то же самое для отладки:

#define __DEBUG_4(...) do{Logger::debug(__VA_ARGS__);}while(0) 

Но в конце концов, после того, как вы определили свой беспроводной уровень регистрации:

#define WIRELESS_LEVEL 5 

вы можете просто вызвать макрос так же, как это:

TRACE(WIRELESS_LEVEL,"wireless: hello world\n"); 

Редактировать В качестве альтернативы (это может быть чище):

#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__) 

Теперь вы можете вызвать вашу функцию как это:

PRINT(DEBUG_LEVEL_TRACE, WIRELESS_LEVEL, "Hello world\n"); 
0

Вы можете получить там переход от макросов встроенных функций. Что-то вроде этого:

// 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)