C:将参数从可变参数函数传递到可变参数宏
C: passing arguments from variadic function to variadic macro
我在我的 C 代码中内置了一个标准日志记录 API,这是一个非常简单的 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 必须在多个嵌入式平台上工作。我刚刚到达一个平台 (Nordic NRF52840),在该平台上,我必须使用的底层日志记录接口显示为 NRF_LOG_INFO(...)
.
形式的可变参数宏
问题:如何正确地将 fn(const char *pFormat, ...)
传递给 BLAH(...)
宏?我的脑袋疼....
这是与 GCC 4.9.3 一起使用的,尽管有一个对 C 编译器版本相对宽松的解决方案会很好。
编辑 1:注意到我可以将我的 logF()
函数重新定义为可变宏并将其映射到那里,问题是我将拥有一个特定于平台的头文件而不是通用头文件,我必须将它向下移动到平台代码中,并且每个都有一个。不是不可能,而是更乱。
编辑 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);
无法将参数从可变参数函数传递到可变参数宏。
因为你想隐藏来自 API header 的平台特定宏调用,你可以使用 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
我在我的 C 代码中内置了一个标准日志记录 API,这是一个非常简单的 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 必须在多个嵌入式平台上工作。我刚刚到达一个平台 (Nordic NRF52840),在该平台上,我必须使用的底层日志记录接口显示为 NRF_LOG_INFO(...)
.
问题:如何正确地将 fn(const char *pFormat, ...)
传递给 BLAH(...)
宏?我的脑袋疼....
这是与 GCC 4.9.3 一起使用的,尽管有一个对 C 编译器版本相对宽松的解决方案会很好。
编辑 1:注意到我可以将我的 logF()
函数重新定义为可变宏并将其映射到那里,问题是我将拥有一个特定于平台的头文件而不是通用头文件,我必须将它向下移动到平台代码中,并且每个都有一个。不是不可能,而是更乱。
编辑 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);
无法将参数从可变参数函数传递到可变参数宏。
因为你想隐藏来自 API header 的平台特定宏调用,你可以使用 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