Спецификатор формата без аргумента
Рассмотрим следующий пример кода:
#define STRING_LITERAL "%u, %u"
const char string_const[ ] = "%u, %u";
snprintf(dest_buff, sizeof(dest_buff), STRING_LITERAL, arg1, arg2, arg3);
Мой компилятор выдает предупреждение: строка формата заканчивается перед этим аргументом
Теперь, если я изменю инструкцию на:
snprintf(dest_buff, sizeof(dest_buff), string_const, arg1, arg2, arg3);
Тогда компилятором не выдается никакого предупреждения.
Мой вопрос: соответствует ли такое поведение стандарту C99?
5 ответов
Предупреждение генерируется компилятором, который смог определить, что вы передали неверные аргументы вызову, а не во втором.
Стандарт определяет, что передача неверных аргументов и / или использование неправильных флагов приводит к неопределенному поведению.
Стандарт не требует предупреждения и является просто дополнительной помощью для программиста.
Мой вопрос: соответствует ли такое поведение стандарту C99?
Оба примера вызывают неопределенное поведение, но нет нарушения ограничений или правила синтаксиса, поэтому диагностика не требуется.
Я нашел следующее заявление в Приложении I (Общие предупреждения) стандарта C99, которое проясняет ситуацию.
1 Реализация может генерировать предупреждения во многих ситуациях, ни одна из которых не указана как часть настоящего международного стандарта. Ниже приведены некоторые из наиболее распространенных ситуаций.
У вас слишком много аргументов, должно быть либо:
#define STRING_LITERAL "%u, %u"
snprintf(dest_buff, sizeof(dest_buff), STRING_LITERAL, arg1, arg2);
или же:
#define STRING_LITERAL "%u, %u, %u"
snprintf(dest_buff, sizeof(dest_buff), STRING_LITERAL, arg1, arg2, arg3);
Причиной отсутствия предупреждения является то, что это неопределенное поведение, и предупреждение выдается только тогда, когда компилятор достаточно умен, чтобы думать, что что-то не так. Если строка находится непосредственно в команде snprintf, компилятор выглядит достаточно умным, если строка передается косвенно, это, по-видимому, не так.
В этом примере
snprintf(dest_buff, sizeof(dest_buff), STRING_LITERAL, arg1, arg2, arg3);
вы передаете строковый литерал напрямую, в то время как в этом
snprintf(dest_buff, sizeof(dest_buff), string_const, arg1, arg2, arg3);
Вы передаете переменную.
Я предполагаю, что ваш компилятор (какой бы он ни был) обрабатывает литералы иначе, чем переменные для целей данного предупреждения.