Код, как показано ниже:
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);
Как исправить эту ошибку?
@RSahu Похоже, только лязг предупреждает в этой ситуации.





Переменная никогда не является строковым литералом. Строковый литерал — это последовательность символов, заключенная в двойные кавычки (например, "foo").
Цель этого предупреждения — предупредить вас, что компилятор не может подтвердить, что типы параметров, заданных для vfptrintf, соответствуют строке формата. Чтобы избавиться от этого предупреждения, вам нужно либо
vfprintf (т.е. vfprintf(sfp, "%d\n", ap))format в объявление функции (спасибо @chris в комментариях):то есть
__attribute__((format(printf, 2, 3)))
void test(FILE* sfp, const char *s, ...)
{
//...
}
Или со стандартизированным синтаксисом атрибута С++ 11:
[[gnu::format(printf, 2, 3)]]
void test(FILE* sfp, const char *s, ...)
{
//...
}
Обратите внимание, что этот последний параметр не является стандартным атрибутом C++ и поэтому не будет работать на всех компиляторах. Например, вам может понадобиться что-то еще, чтобы успокоить MSVC. По стандарту компиляторы должны игнорировать неизвестные атрибуты, если вы используете синтаксис C++11, но они все равно могут выдать предупреждение об этом, вернув вас обратно в ту же ситуацию, в которой вы находитесь сейчас.
Вы также все равно будете вызывать предупреждение, если test вызывается со вторым аргументом, который сам по себе не является строковым литералом.
В качестве примечания: похоже, что clang в любом случае не может проверять типы аргументов функций va_listprintf, поэтому -Wformat-nonliteral на самом деле бесполезен в этом случае. GCC не выдает это предупреждение, вероятно, именно по этой причине.
Кажется, ошибка исчезнет, если вы сообщите Clang, что параметр является строкой формата через __attribute__((format(printf, 2, 3)))
Спасибо, что указали на это @chris. Добавил в ответ.
Не уверен, почему я не попробовал это, но лучший вариант, вероятно, [[gnu::format(printf, 2, 3)]]. Если компилятор не может его понять, компилятор должен его игнорировать.
вы не можете преобразовать переменную в строковый литерал