C++可变参数模板函数中格式字符串非字面量警告的解决办法
解决C++可变参数模板log函数的printf格式安全警告及类型匹配问题
你遇到的问题是:用C++可变参数模板实现的log函数调用printf时,触发了format string is not a string literal的编译警告,改成C风格可变参数虽然能通过属性解决,但想保留模板风格;用boost::format替代又会出现类型匹配问题(比如uint8_t无法被%u正确解析)。
可行解决方案:给模板函数添加printf格式属性
GCC、Clang(以及兼容它们的编译器)支持给C++模板函数添加__attribute__((format))属性,让编译器将其当作printf风格函数进行检查,既保留模板特性,又消除警告,同时完全沿用printf的类型处理逻辑。
代码示例:
// 声明时添加格式属性 template <typename... Types> inline static void log(const char* inputString, Types... args) __attribute__((format(printf, 1, 2))); // 函数定义 template <typename... Types> inline static void log(const char* inputString, Types... args) { printf(inputString, args...); }
- 参数说明:
format(printf, 1, 2)中,1表示格式字符串是函数的第1个参数,2表示可变参数从第2个参数开始。 - 效果:编译器会像检查原生printf一样检查你的log函数,消除
format-security警告,同时uint8_t a = 1; log("%u", a);会和原生printf一样正常输出1,不会出现boost::format的类型匹配问题。
如果需要兼容MSVC,可以用__declspec(format(printf, 1, 2))替代上述属性,跨平台场景可以用宏做条件编译:
#ifdef _MSC_VER #define PRINTF_FORMAT_ATTR(fmt_pos, args_pos) __declspec(format(printf, fmt_pos, args_pos)) #else #define PRINTF_FORMAT_ATTR(fmt_pos, args_pos) __attribute__((format(printf, fmt_pos, args_pos))) #endif template <typename... Types> inline static void log(const char* inputString, Types... args) PRINTF_FORMAT_ATTR(1, 2); template <typename... Types> inline static void log(const char* inputString, Types... args) { printf(inputString, args...); }
为什么这个方案比boost::format更合适?
这个方案直接复用了printf的类型处理逻辑,所有printf支持的格式符和类型匹配规则都能原样生效,完全避免了boost::format对类型的严格匹配限制,同时保留了C++可变参数模板的灵活性。
内容的提问来源于stack exchange,提问作者Paweł Richert
相关产品推荐
相关产品推荐

