Спецификатор формата без аргумента

Рассмотрим следующий пример кода:

#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);

Вы передаете переменную.

Я предполагаю, что ваш компилятор (какой бы он ни был) обрабатывает литералы иначе, чем переменные для целей данного предупреждения.

Другие вопросы по тегам