将零参数包传递给printf

时间:2015-03-30 15:12:46

标签: c++ gcc variadic

我创建了一个具有可变参数模板方法的类。此方法调用printf函数。将零参数传递给方法时,我会收到gcc的编译警告:

  

警告:格式不是字符串文字而没有格式参数[-Wformat-security]

一个简化的类示例是:

class printer{
    std::map<int,std::string> str;
  public:
    printer(){
      str[0] = "null\n";
      str[1] = "%4d\n";
      str[2] = "%4d %4d\n";
      str[3] = "%4d %4d\n%4d\n";
    }
    template<typename ...Args>
    void print(Args... args){
      printf(str[sizeof...(args)].c_str(),args...);
    }
};

使用时

printer p;
p.print(23);
p.print(345,23);

一切顺利编译,但在使用时

printer p;
p.print();

我收到编译警告

main.cpp: In instantiation of ‘void printer::print(Args ...) [with Args = {}]’:
main.cpp:23:11:   required from here
main.cpp:17:50: warning: format not a string literal and no format arguments [-Wformat-security]
       printf(str[sizeof...(args)].c_str(),args...);

当然如果我打电话

printf("null\n");

没有出现警告。

有人可以解释为什么会这样吗?

我可以在不禁用-Wformat-security标志的情况下删除警告吗?

1 个答案:

答案 0 :(得分:12)

这是一个预期的警告,如果我们查看-Wformat-security的文档,它会说:

  

-Wformat安全       如果指定了-Wformat,还会警告使用表示可能存在安全问题的格式函数。目前,会警告调用printf和scanf函数,其中格式字符串不是字符串文字,并且没有格式参数,如printf(foo); 。如果格式字符串来自不受信任的输入并且包含“%n&#39;”,则这可能是安全漏洞。 (目前这是-Wformat-nonliteral警告的子集,但是将来警告可能会添加到-Wformat-nonliteral中未包含的-Wformat-security。)   -Wformat = 2

因为c_str()的结果不是字符串文字而没有传递参数的情况。

这种情况:

printf("null\n");

不会发出警告,因为"null\n"是不可能从用户输入的字符串文字。

我们可以从%n format specifier program giving different outputs on different compilers. Why?中了解为什么这是一个潜在的安全问题。

如果你不想要所有的-Wformat-secrity,你似乎必须打开特定的开关:

  

-Wformat包含在-Wall中。为了更好地控制格式检查的某些方面,选项-Wformat-y2k,-Wno-format-extra-args,-Wno-format-zero-length,-Wformat-nonliteral,-Wformat-security和-Wformat = 2是可用的,但不包括在-Wall中。

虽然如果-Wformat-secrity稍后添加更多选项,这是不好的选择,那么您需要不断更新。

AndyG提到的另一种选择是过载:

void print(){
  std::printf("null\n");
}