C: передача аргументов из функции variadi c в макрос variadi c - PullRequest
6 голосов
/ 25 марта 2020

У меня есть стандартный API ведения журнала, встроенный в мой код C, замечательная простая вещь logF(const char *pFormat, ...), которая до сих пор всегда отображалась на vprintf(), то есть:

void logF(const char *pFormat, ...)
{
    va_list args;
    va_start(args, pFormat);
    vprintf(pFormat, args);
    va_end(args);
}

C код выше этого API должен работать на нескольких встроенных платформах. Я только что достиг платформы (Nordi c NRF52840), где базовый интерфейс ведения журналов, с которым мне приходится работать, представлен в виде макроса variadi c в форме NRF_LOG_INFO(...).

ВОПРОС: как это сделать? Я правильно передал fn(const char *pFormat, ...) в BLAH(...) макрос? Мой мозг болит ....

Это с G CC 4.9.3, хотя было бы неплохо иметь решение, которое относительно расслаблено относительно C версии компилятора.

РЕДАКТИРОВАТЬ 1: отметил, что я мог бы переопределить мою функцию logF(), чтобы она была макросом variadi c и отобразить ее там, проблема в том, что тогда у меня будет файл заголовка c, определяемый платформой, а не универсальный c Во-первых, мне нужно было бы перенести его в код платформы и иметь по одному для каждого. Не невозможно, но более грязно.

РЕДАКТИРОВАТЬ 2: Меня спросили о том, как NRF_LOG_INFO() расширяется. Вот соответствующий вывод препроцессора:

#define NRF_LOG_INFO(...) NRF_LOG_INTERNAL_INFO( __VA_ARGS__)

#define NRF_LOG_INTERNAL_INFO(...) NRF_LOG_INTERNAL_MODULE(NRF_LOG_SEVERITY_INFO, NRF_LOG_SEVERITY_INFO, __VA_ARGS__)

#define NRF_LOG_INTERNAL_MODULE(level,level_id,...) if (NRF_LOG_ENABLED && (NRF_LOG_LEVEL >= level) && (level <= NRF_LOG_DEFAULT_LEVEL)) { if (NRF_LOG_FILTER >= level) { LOG_INTERNAL(LOG_SEVERITY_MOD_ID(level_id), __VA_ARGS__); } }

#define LOG_INTERNAL(type,...) LOG_INTERNAL_X(NUM_VA_ARGS_LESS_1( __VA_ARGS__), type, __VA_ARGS__)

#define LOG_INTERNAL_X(N,...) CONCAT_2(LOG_INTERNAL_, N) (__VA_ARGS__)

Then depending on number of args, anything up to:

#define LOG_INTERNAL_6(type,str,arg0,arg1,arg2,arg3,arg4,arg5) nrf_log_frontend_std_6(type, str, (uint32_t)(arg0), (uint32_t)(arg1), (uint32_t)(arg2), (uint32_t)(arg3), (uint32_t)(arg4), (uint32_t)(arg5))

void nrf_log_frontend_std_6(uint32_t severity_mid,
                            char const * const p_str,
                            uint32_t val0,
                            uint32_t val1,
                            uint32_t val2,
                            uint32_t val3,
                            uint32_t val4,
                            uint32_t val5);

1 Ответ

3 голосов
/ 25 марта 2020

Невозможно передать аргументы из функции variadi c в макрос variadi c.

Поскольку вы хотите скрыть вызов макроса спецификаций платформы c из заголовка API, который вы может обработать аргументы функции с помощью vsnprintf вместо vprintf и вызвать макрос ведения журнала с форматом "%s" и результирующий строковый буфер.

void logF(const char *pFormat, ...)
{
    va_list args;
    /* Choose a reasonable size or replace with dynamic allocation based on the return value of vsnprintf */
    /* This could also be a static variable or a global variable to avoid allocation of a big buffer on the stack. */
    char buffer[1024];

    va_start(args, pFormat);
    vsnprintf(buffer, sizeof(buffer), pFormat, args);

    NRF_LOG_INFO("%s", buffer);

    va_end(args);
}

Обратите внимание, что вам может потребоваться вызвать NRF_LOG_FLUSH перед буфер выходит из области видимости или перезаписывается. См https://devzone.nordicsemi.com/f/nordic-q-a/22647/nrf_log_info-how-to-print-log-with-string-parameter

...