如何使用C++预处理器替换带::的类静态方法以实现日志格式串校验?
可行解决方案
方案1:给自定义日志方法添加编译器格式检查属性(最推荐)
你不需要将日志调用替换为fprintf,直接给MyLogger的相关方法添加GCC/Clang/MSVC通用的格式检查属性,即可在编译期实现和printf完全一致的格式串与参数匹配校验,零侵入现有业务代码。
属性写法示例:
class MyLogger { public: // __attribute__ format参数说明:第二个参数2代表格式串是第2个参数,第三个参数3代表可变参数从第3个开始(第一个参数是隐式的this指针) static void Error(const char* format, ...) __attribute__((format(printf, 2, 3))); static void Warn(const char* format, ...) __attribute__((format(printf, 2, 3))); };
如果使用MSVC编译器,改用_Printf_format_string_注解格式串参数即可:
static void Error(_Printf_format_string_ const char* format, ...);
开启编译警告后,编译器会直接输出格式不匹配的报错信息,完全满足你提前排查问题的需求。
方案2:预处理器替换适配方案
C预处理器的宏名确实不支持包含::符号,可以通过两种思路绕开限制:
- 思路A:新增一层宏包装日志接口
先定义全局日志宏,把现有代码中所有MyLogger::Error(替换为MY_LOG_ERROR(:
后续切换检查逻辑只需要修改宏定义,不需要改动业务调用代码。// 正常版本 #define MY_LOG_ERROR(fmt, ...) MyLogger::Error(fmt, ##__VA_ARGS__) // 编译检查版本,直接替换为fprintf触发原生检查 #define MY_LOG_ERROR(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__) - 思路B:临时抹平命名空间前缀做编译检查
仅在需要做格式检查的编译批次中,在全局头文件最前面添加以下宏定义,不需要修改业务代码:
注意该宏仅用于编译期检查,发布生产版本时需要移除,避免实际调用逻辑被替换。// 先把类名定义为空,让预处理器能识别后续的方法名宏 #define MyLogger #define Error(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__)
内容的提问来源于stack exchange,提问作者ATV
相关产品推荐
相关产品推荐

