Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/127.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 将零参数包传递给printf_C++_Gcc_Variadic - Fatal编程技术网

C++ 将零参数包传递给printf

C++ 将零参数包传递给printf,c++,gcc,variadic,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

我创建了一个具有可变模板方法的类。此方法调用
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
标志的情况下删除警告吗?

这是一个预期的警告,如果我们查看文档中的说明:

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

由于
c_str()
的结果不是字符串文字,因此不传递任何参数就是这种情况

本案:

printf("null\n");
不发出警告,因为
“null\n”
是一个字符串文字,不可能从用户输入

我们可以从中看出为什么这是一个潜在的安全问题

如果您不想使用所有的
-Wformat security
,则必须打开特定的开关:

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

虽然如果以后
-Wformat security
添加了更多选项,这是一个糟糕的选项,但是您需要不断地更新

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

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

我问了一个几乎相同的问题。不要将此标记为重复,因为我不确定您是否可以在我建议的解决方案中使用类似的宏。如果它工作,请把它复制。现在C++有<代码> Prtff < /代码>吗?您正在调用C
printf
…@AnttiHaapala有
std::printf
…)将OP的
print
函数重载为一个不带参数的函数(一个“不做任何事情”的函数)是不是一个好主意?我不明白的是:为什么无文字警告只在零参数情况下出现,而在其他情况下不出现?@ctheo请看my的例子,了解为什么无参数情况是一个问题。@AndyG是的,我想补充一下,不得不走开。谢谢@ShafikYaghmour。因此,可以通过
-Wformat nonliteral
选项来避免警告。现在的挑战是如何真正保护软件免受格式化攻击。也许我稍后会发布另一个问题。