Проверка времени компиляции с помощью директив препроцессора C

Есть ли способ сделать так, чтобы проверка уровня журнала в моем LOGGING-макросе (показанном ниже) происходила во время компиляции? Это должно быть возможно, поскольку во время компиляции уже известно, является ли условие (if (pLogLevel ‹= LOG_LEVEL)) истинным или ложным. Вот пример того, как можно использовать макрос:

LOGGING(LOG_DEBUG, "FALSE - Wrong Marker\n");

Первоначально я думал, что #ifdirectives в #define могут мне помочь, но эта статья показала мне, что это было бы невозможно. Это исходный код моей проблемы:

#ifndef __LOGGING_H__
#define __LOGGING_H__ 1

#include <time.h>

#define LOG_EMERG    0   
#define LOG_ALERT    1   
#define LOG_CRIT     2   
#define LOG_ERROR    3   
#define LOG_WARN     4   
#define LOG_NOTICE   5   
#define LOG_INFO     6   
#define LOG_DEBUG    7   
#define LOG_NONE     8   

/* set the global logging level here */
#define LOG_LEVEL LOG_INFO

void print_timestamp(void);

#if LOG_LEVEL == LOG_DEBUG
#define _LOG_PREAMBLE                                       \   
        fprintf(stdout, "%s:%d ", __FILE__, __LINE__);
#else
#define _LOG_PREAMBLE                                       \   
        print_timestamp();
#endif

#if LOG_LEVEL == LOG_EMERG
#define _LOG_LEVEL fprintf(stdout, "EMERG "); 
#elif LOG_LEVEL == LOG_ALERT
#define _LOG_LEVEL fprintf(stdout, "ALERT "); 
#elif LOG_LEVEL == LOG_CRIT
#define _LOG_LEVEL fprintf(stdout, "CRIT "); 
#elif LOG_LEVEL == LOG_ERROR
#define _LOG_LEVEL fprintf(stdout, "ERROR "); 
#elif LOG_LEVEL == LOG_WARN
#define _LOG_LEVEL fprintf(stdout, "WARN "); 
#elif LOG_LEVEL == LOG_NOTICE
#define _LOG_LEVEL fprintf(stdout, "NOTICE "); 
#elif LOG_LEVEL == LOG_INFO
#define _LOG_LEVEL fprintf(stdout, "INFO "); 
#elif LOG_LEVEL == LOG_INFO
#define _LOG_LEVEL fprintf(stdout, "DEBUG "); 
#else
#define _LOG_LEVEL
#endif

#define LOGGING(pLogLevel, ...)                               \   
    /* change this to compile time conditional if possible */ \   
    if (pLogLevel <= LOG_LEVEL)                               \   
    {                                                         \   
        _LOG_PREAMBLE                                         \   
        _LOG_LEVEL                                            \   
        fprintf(stdout, ##__VA_ARGS__);                       \   
    }   

#endif /* __LOGGING_H__ */

person dubbaluga    schedule 31.08.2012    source источник
comment
Скорее всего, компилятор исключит код вашего макроса LOGGING (), когда условие ложно, когда вы включите оптимизацию, а также исключит условную проверку if (), когда условие истинно - оставив только тело if () осталось в коде. Если бы этого не произошло, я бы отправил это компилятору как ошибку.   -  person nos    schedule 01.09.2012
comment
Это работа генератора кода. Он может видеть, что оператор if () всегда ложен и знает, как устранить код. Вам не нужно помогать, просто убедитесь, что оптимизатор включен.   -  person Hans Passant    schedule 01.09.2012
comment
Спасибо вам двоим. Это полезные комментарии. Определенно имеет смысл, что компилятор или оптимизатор включает / отключает код в условных выражениях, которые всегда истинны или ложны соответственно.   -  person dubbaluga    schedule 07.09.2012


Ответы (2)


Один из подходов - объединить уровень журнала в макрос ведения журнала.

Это создаст набор макросов, которые будут включаться или отключаться в зависимости от уровня журнала.

Вы можете использовать эти макросы, и они будут появляться или нет в зависимости от уровня журнала во время компиляции. Таким образом, они будут использоваться следующим образом.

LOGGING_LEVEL_DEBUG("a Debug log.");
//.... some code
LOGGING_LEVEL_EMERG("a Emerge log.");

Таким образом, определения макросов будут выглядеть примерно так:

    #define LOG_EMERG    0   
    #define LOG_ALERT    1   
    #define LOG_CRIT     2   
    #define LOG_ERROR    3   
    #define LOG_WARN     4   
    #define LOG_NOTICE   5   
    #define LOG_INFO     6   
    #define LOG_DEBUG    7   
    #define LOG_NONE     8   

    /* set the global logging level here */
    #define LOG_LEVEL LOG_INFO

    void print_timestamp(void);

    #if LOG_LEVEL >= LOG_DEBUG
    #define _LOG_PREAMBLE                                       \
            fprintf(stdout, "%s:%d ", __FILE__, __LINE__);
    #else
    #define _LOG_PREAMBLE                                       \
            print_timestamp();
    #endif

    #if LOG_LEVEL >= LOG_EMERG
        #define LOGGING_LEVEL_EMERG(...) \
            {                                                         \
                _LOG_PREAMBLE                                         \
                fprintf(stdout, "EMERG ");                                           \
                fprintf(stdout, ##__VA_ARGS__);                       \
            }   

        #else
        #define LOGGING_LEVEL_EMERG(...)
        #endif

        #if LOG_LEVEL >= LOG_ALERT
        #define LOGGING_LEVEL_ALERT(...) \
            {                                                         \
                _LOG_PREAMBLE                                         \
                fprintf(stdout, "ALERT ");                                           \
                fprintf(stdout, ##__VA_ARGS__);                       \
            }   

        #else
        #define LOGGING_LEVEL_ALERT(...)
        #endif
person Richard Chambers    schedule 31.08.2012

Сами макросы можно было определить условно:

#if LOG_LEVEL > 0
#  define LOG(...) printf(__VA_ARGS__)
#else
#  define LOG(...)
#endif

#if LOG_LEVEL > 1
// and so forth
person Kerrek SB    schedule 31.08.2012