在编译时,C ++中针对printf格式检查参数的可移植方法

时间:2015-02-19 15:36:25

标签: c++ c++11

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

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

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

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

目前,我需要在英特尔C ++编译器(ICC)和GCC上进行编译。如果我能在ICC中实现属性检查,那就不错了。如果在编译时有一个纯C ++语言技巧来进行这样的检查,那就太棒了。

3 个答案:

答案 0 :(得分:1)

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

由于您的项目是C ++,为什么不使用C ++习语并使用boost::formathttp://www.boost.org/doc/libs/1_57_0/libs/format/doc/format.html)或IO流?然后你得到类型安全,甚至不用担心验证输入。

答案 1 :(得分:1)

正如其他答案所说,没有便携/标准的方式来实现问题所要求的。但是,英特尔C / C ++编译器(icc和icpc)与GNU函数属性 100%兼容。见Intel XE13。当我声明__attribute__((format())).

时,icpc会给出-Wformat警告

答案 2 :(得分:0)

没有可移植的方法。

您可以使用可变参数模板在运行时检查参数,但它会降低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});
}