Являются ли предупреждения компилятора printf / sprintf концептуальным разрывом? - PullRequest
4 голосов
/ 14 сентября 2010

Я заметил, что большое количество компиляторов C выдают предупреждения, когда спецификаторы преобразования в строке формата функций printf / sprintf не соответствуют типу или количеству соответствующих аргументов.

Мне кажется, что это концептуальный разрыв, поскольку в C нет встроенных функций в соответствии со спецификацией языка.

Все, что должен знать компилятор о printf / sprintf, это их прототипы, а не их семантика. Я знаю, что printf / sprintf являются стандартными функциями C, но все же они находятся в отдельной библиотеке libc, и вы должны включить stdio.h для импорта их прототипов.

Вместо этого многие компиляторы анализируют строку формата, которая также может быть предоставлена ​​во время выполнения.

Имеет ли смысл вышесказанное?

Ответы [ 6 ]

11 голосов
/ 14 сентября 2010

«Все, что должен знать компилятор о printf / sprintf, это их прототипы, а не их семантика».

Это та часть, которая не соответствует действительности. Что касается стандарта, любой части реализации C "разрешено" знать о любой другой части и выпускать диагностические данные, которые могут быть полезны для пользователя. Встроенные функции компилятора не требуются стандартом, как и эта конкретная диагностика, но они, безусловно, не запрещены.

Обратите внимание, что (что касается стандарта) стандартная библиотека является особенной, это не просто старая связанная библиотека. Если конкретная реализация / компилятор даже предоставляет пользователю механизм для связи с другой версией стандартной библиотеки, стандарт определенно не требует, чтобы он «работал», когда эта альтернативная библиотека имеет семантику, отличную от той, что изложена в стандарт.

Таким образом, в этом смысле все в стандартной библиотеке является «встроенными». Это часть спецификации языка Си. Компиляторам разрешается действовать при условии, что они ведут себя так, как требует стандарт.

Конечно, если спецификатор формата не известен до времени выполнения, тогда компилятор не может выполнить статическую проверку varargs. Но когда это известно во время компиляции, компилятор может принять поведение printf так же верно, как и поведение memcpy или целочисленного сложения.

2 голосов
/ 14 сентября 2010

Стандарт требует диагностики при некоторых обстоятельствах, но не запрещает общую диагностику.Любая реализация может выдавать диагностическую информацию по любой причине, включая неправильное использование printf() или злоупотребление буквой Q. Очевидно, что некоторые из этих причин более полезны, чем другие.

Более того, если вы включитебиблиотека, все видимые идентификаторы в ней становятся зарезервированными.Вы не можете #include <stdio.h> и иметь собственное определение printf (см. 7.1.3 проекта стандарта C99).Это означает, что реализация может свободно предполагать, что вы используете стандарт printf, и обращаться с ним, как с обязательной частью стандарта.

2 голосов
/ 14 сентября 2010

Задача компилятора здесь просто дать вам несколько полезных советов. Такое поведение не охватывается стандартом.

Реализация может генерировать предупреждения во многих ситуациях, ни одна из которых не является указано как часть настоящего международного стандарта.

Теоретически, ничто не мешает компилятору предупреждать вас о (потенциально) неправильном использовании, скажем, библиотеки QT.

И printf - это стандартная функция в том смысле, что она (включая ее семантику) охватывается стандартом ISO C.

2 голосов
/ 14 сентября 2010

Если я правильно прочитал ваш вопрос, я согласен с вашей предпосылкой, что проверка printf и строк формата друзей компилятором является концептуальным действием, в отличие от других видов статической проверки (синтаксис, тип и т. Д.), Выполняемой компилятор.

Однако это разрешено стандартом и очень помогает нам, бедным программистам.

1 голос
/ 14 сентября 2010

Конечная цель стандартов языка программирования - помочь программистам писать программы, которые ведут себя так, как задумано. В стандарте нет ничего, что говорило бы, что компилятор должен выдать предупреждение, если он встречает «bigvar = byte3 << 24 + byte2 << 16 + byte1 << 8 + byte0;», но так как результаты, вероятно, не те, что программист Предполагается, что многие компиляторы выдают предупреждение. Единственное ограничение, которое стандарты накладывают на предупреждения, состоит в том, что они не должны препятствовать успешной компиляции легитимной программы (например, компилятора, который завершился с ошибкой после вывода 999 предупреждений, или который выдает столько предупреждений, что компиляция для всех практических целей никогда не завершится, будет не соответствующим). </p>

Нет никакого требования, чтобы компилятор "знал" о стандартных библиотеках, но также нет требования, чтобы он не знал о них, если кто-то # включает нормальные заголовки. Действительно, , если программа включает в себя . Я думаю, что по стандарту для компилятора будет допустимо заменить вызов printf, который он может понять, на что-то, что может быть легче обработать во время выполнения (например, он может заменить printf ("Q% 5d", foo); на "putch ('Q'); __put_int (foo, 5);" при желании). Если программа не #include , такой перевод будет запрещен.

1 голос
/ 14 сентября 2010

Такого рода предупреждения указывают на возможные ошибки и, как следствие, полезны.

Да, может показаться непоследовательным иметь специальные случаи для предупреждений в компиляторе (при условии, что <stdio.h> не просто имеет атрибут __printf_format_warning или что-то в этом роде), но опять же, если это полезно и помогает решить некоторые ошибки (возможно, даже ошибки безопасности), тогда почему бы их не иметь?

Я имею в виду, что не все просто заменяют свои libc на свои, с другой семантикой printf ...

...