如何使变量成为文字字符串

时间:2019-05-18 04:02:10

标签: c++

代码如下:

FILE *sfp;
....

void test(char *s, ...)
{
  va_list ap;
  va_start(ap, s);
  vfprintf(sfp, s, ap);
  fflush(sfp);
  va_end(ap);
}

下面报告了编译错误:

error: format string is not a string literal [-Werror,-Wformat-nonliteral]
  vfprintf(sfp, s, ap);

如何解决此错误?

1 个答案:

答案 0 :(得分:2)

变量永远不是字符串文字。字符串文字是由双引号(即"foo")包围的字符序列。

该警告的目的是警告您编译器无法确认分配给vfptrintf的参数类型与格式字符串匹配。要消除该警告,您将需要

  1. 将文字格式的字符串传递给vfprintf(即vfprintf(sfp, "%d\n", ap)
  2. 禁用(或更确切地说,不要启用)该警告,并接受如果您的参数与格式说明符不匹配的情况,编译器将不会警告您。
  3. format属性添加到函数声明中(感谢注释中的@chris):

__attribute__((format(printf, 2, 3)))
void test(FILE* sfp, const char *s, ...)
{
    //...
}

或使用标准化的C ++ 11属性语法:

[[gnu::format(printf, 2, 3)]]
void test(FILE* sfp, const char *s, ...)
{
    //...
}

请注意,最后一个选项不是标准的C ++属性,因此不适用于所有编译器。例如,您可能还需要其他一些来安抚MSVC。按照标准,如果您使用C ++ 11语法,则编译器应忽略未知属性,但它们仍可能会发出警告,使您回到现在的状况。

如果使用另一个本身不是字符串文字的第二个参数调用test,您仍然会发出警告。


作为旁注,clang似乎无法检查va_list printf函数的参数类型,因此-Wformat-nonliteral在这种情况下实际上没有帮助。 GCC不会发出此警告,可能正是由于该原因。