一种在编译时用C++根据printf格式检查参数的可移植方法

portable way of checking parameters against printf format in compile time, C++

本文关键字:格式 printf 根据 检查 参数 方法 可移植 C++ 一种 编译      更新时间:2023-10-16

我有一个日志函数my_log(const char* my_fmt, ...),用于自定义日志记录。我希望my_log遵循printf惯例。为了省去我的麻烦,我想警告用户printf()会发出的任何警告和错误。我需要的printf功能是-Wformat警告。当然还有错误。

问题:如何在没有任何运行时开销的情况下实现这一点?(不使用编译器特定功能)。

在GCC中,我可以使用__attribute__((format()))

void __attribute__((format(printf,1,2))) my_log(const char* fmt, ...){ }

现在,我需要在英特尔C++编译器(ICC)和GCC上进行编译。如果我能在ICC中实现属性检查,那就太好了。如果有一个纯粹的C++语言技巧可以在编译时进行这样的检查,那将是非常棒的。

没有可移植的方法。即使对于printf系列,该语言也允许编译器假设您知道自己在做什么,并编译您所写的内容,尽管如果您启用g++,它确实会提供有用的警告。

既然你的项目是C++,为什么不使用C++习语并使用boost::format呢(http://www.boost.org/doc/libs/1_57_0/libs/format/doc/format.html)还是IO流?然后您就可以获得类型安全性,甚至不需要担心验证输入。

正如其他答案所说,没有可移植/标准的方法来实现问题的要求。但是,英特尔C/C++编译器(icc和icpc)与GNU函数属性是100%兼容的。请参阅英特尔XE13。当我声明__attribute__((format())). 时,icpc确实会发出-Wformat警告

没有可移植的方法。

您可以在运行时使用可变模板来检查参数,但这会减慢my_log()的速度。

此外,您可以尝试以下解决方案,但my_log()将不遵循printf约定。

#include <iostream>
#include <initializer_list>
#include <sstream>
class UC
{
    static std::stringstream ss;
    std::string str;
    friend const char *Str(std::initializer_list<UC> data);
public:
    template <class T> UC(T param) : str((ss.str(""), ss << param, ss.str())) {}
};
std::stringstream UC::ss;
void my_log(std::initializer_list<UC> data)
{
    std::string in_str;
    for (auto it = data.begin(); it != data.end(); it++)
        ret += it->str;
    std::cout << in_str.c_str() << 'n'; // Or whatever you want to do with your string.
}

int main()
{
    my_log({"Hello", '!', 11});
}