13.8 Определённые изменения, которых мы не хотим внедрять
В этом разделе перечислены изменения, которые часто запрашивают пользователи, но которые мы не внедряем, так как считаем, что GCC лучше без них.
- Проверка количества и типов аргументов функции со старой дефиницией без прототипа.
Такая функция будет работать только в некоторых случаях — только для вызовов, которые находятся в том же файле, что и вызываемая функция, после её определения. Единственный способ надёжно проверить все вызовы — добавить прототип для функции. Но добавление прототипа лишает этой функции смысла. Поэтому эта функция не стоит усилий.
- Предупреждение об использовании выражения со знаком как сдвигающего счётчика.
Операнды сдвига, скорее всего, чаще бывают со знаком, чем без знака. Предупреждение об этом вызовет больше неудобств, чем пользы.
- Предупреждение об присваивании значения со знаком беззнаковой переменной.
Такие присваивания должны быть очень распространены; предупреждение об этом вызовет больше неудобств, чем пользы.
- Предупреждение, когда значение ненулевой функции игнорируется.
C содержит много стандартных функций, возвращающих значение, которое большинство программ предпочитают игнорировать. Яркий пример —
printf. Предупреждение об этой практике только заставит защищённого программиста засорять программы десятками приведений кvoid. Такие приведения требуются так часто, что превращаются в визуальный шум. Написание этих приведений становится настолько автоматическим, что они больше не передают полезной информации о намерениях программиста. Для функций, где возвращаемое значение никогда не должно игнорироваться, используйте атрибут функцииwarn_unused_result(см. Атрибуты функций). - Установление -fshort-enums в качестве значения по умолчанию.
Это привело бы к несовместимости структуры хранения с большинством других компиляторов C. И это не кажется очень важным, учитывая, что тот же результат можно получить другими способами. Самый важный случай — когда перечисление-значений хранится в структуре, и в этом случае можно явно указать ширину поля.
- По умолчанию делать битовые поля беззнаковыми на определённых машинах, где «стандарт ABI» так и говорит.
Стандарт ISO C предоставляет компилятору возможность определить, является ли битовое поле, объявленное как
int, со знаком или без знака. Это, по сути, создаёт два альтернативных диалекта C.Компилятор GNU C поддерживает оба диалекта; вы можете указать диалект со знаком с помощью -fsigned-bitfields, а без знака с помощью -funsigned-bitfields. Однако это оставляет открытым вопрос о том, какой диалект использовать по умолчанию.
В настоящее время предпочтительный диалект делает обычные битовые поля со знаком, так как это проще. Поскольку
intидентичноsigned intво всех других контекстах, лучше, чтобы они были идентичны и в битовых полях.Некоторые производители компьютеров опубликовали стандарты двоичного интерфейса приложения, в которых указывается, что обычные битовые поля должны быть беззнаковыми. Однако ошибочно делать какие-либо заявления об этой проблеме в ABI. Это связано с тем, что обработка обычных битовых полей различает два диалекта C. Оба диалекта имеют смысл на каждом типе машин. То, был ли определённый объектный файл скомпилирован с использованием битовых полей со знаком или без знака, не имеет значения для других объектных файлов, даже если они обращаются к тем же битовым полям в одних и тех же структурах данных.
Программа написана на одном из этих двух диалектов. Программа имеет шанс работать на большинстве машин, если она скомпилирована с правильным диалектом. Она вряд ли будет вообще работать, если скомпилирована с неправильным диалектом.
Многие пользователи ценят компилятор GNU C, потому что он обеспечивает единообразную среду на разных машинах. Эти пользователи испытывали бы неудобства, если бы компилятор обрабатывал обычные битовые поля по-разному на определённых машинах.
Иногда пользователи пишут программы, предназначенные только для определённого типа машины. В этих случаях пользователи выиграют, если компилятор GNU C будет поддерживать по умолчанию тот же диалект, что и другие компиляторы на этой машине. Но такие приложения редки. И пользователи, пишущие программу для работы на нескольких типах машин, не могут извлечь выгоды из такого рода совместимости.
Вот почему GCC будет и впредь обрабатывать обычные битовые поля одинаково на всех типах машин (по умолчанию).
Есть некоторые доводы в пользу того, чтобы по умолчанию делать битовые поля беззнаковыми на всех машинах. Если, например, это станет всеобщим фактическим стандартом, это будет разумно, если GCC будет ему следовать. Это следует учитывать в будущем.
(Конечно, пользователи, серьёзно озабоченные переносимостью, должны явно указывать в каждом битовом поле, со знаком оно или без. Таким образом, они пишут программы, имеющие одинаковый смысл в обоих диалектах C.)
- Отмена определения
__STDC__при отсутствии -ansi.В настоящее время GCC определяет
__STDC__безусловно. Это даёт хорошие результаты на практике.Программисты обычно используют условные операторы в
__STDC__, чтобы выяснить, безопасно ли использовать определённые возможности ISO C, такие как прототипы функций или конкатенация токенов ISO. Поскольку простойgccподдерживает все возможности ISO C, правильный ответ на эти вопросы — «да».Некоторые пользователи пытаются использовать
__STDC__для проверки наличия определённых функций библиотеки. Это на самом деле неправильное использование в программе ISO C, потому что стандарт ISO C гласит, что совместимая реализация без среды выполнения должна определять__STDC__, даже если она не имеет функций библиотеки. ‘gcc -ansi -pedantic’ — это совместимая реализация без среды выполнения, и поэтому она обязана определить__STDC__, даже если она не поставляется с библиотекой ISO C.Иногда люди говорят, что определение
__STDC__в компиляторе, который не полностью соответствует стандарту ISO C, каким-то образом нарушает стандарт. Это нелогично. Стандарт — это стандарт для компиляторов, которые заявляют о поддержке ISO C, таких как ‘gcc -ansi’ — а не для других компиляторов, таких как простойgcc. Что бы ни говорило о стандарте ISO C, это важно для дизайна простогоgccбез -ansi, только по практическим соображениям, а не как требование.GCC обычно определяет
__STDC__как 1 и дополнительно определяет__STRICT_ANSI__, если вы укажете опцию -ansi или опцию -std для строгого соответствия какой-либо версии ISO C. На некоторых хостах файлы системных включений используют другую конвенцию, где__STDC__обычно равно 0, но равно 1, если пользователь указывает строгое соответствие стандарту C. GCC следует конвенции хоста при обработке файлов системных включений, но при обработке пользовательских файлов следует общепринятой конвенции GNU C. - Отмена определения
__STDC__в C++.Программы, написанные для компиляции с помощью трансляторов C++ в C, получают значение
__STDC__от компилятора C, который используется впоследствии. Эти программы должны проверить__STDC__, чтобы определить, какой тип препроцессора C использует компилятор: должны ли они конкатенировать токены в стиле ISO C или в традиционном стиле.Эти программы работают правильно с GNU C++ если
__STDC__определено. В противном случае они не будут работать.Кроме того, многие файлы заголовков написаны для предоставления прототипов в ISO C, но не в традиционном C. Многие из этих файлов заголовков могут работать без изменений в C++, при условии, что
__STDC__определено. Если__STDC__не определено, они все потерпят неудачу и все им придётся измениться, чтобы явно проверить и C++. - Удаление «пустых» циклов.
Исторически GCC не удалял «пустые» циклы, исходя из предположения, что наиболее вероятная причина их включения в программу — задержка, поэтому их удаление не сделает реальные программы быстрее.
Однако, здесь рассуждение таково, что оптимизация непустого цикла не может привести к пустому. Это было верно для тщательно написанного C, скомпилированного с менее мощными оптимизаторами, но не всегда верно для тщательно написанного C++ или с более мощными оптимизаторами. Таким образом, GCC удалит операции из циклов, когда сможет определить, что эти операции не видны снаружи (кроме времени их выполнения, конечно). В случае, если цикл можно доказать конечным, GCC также удалит сам цикл.
Учитывайте это при выполнении тестов времени выполнения, например, следующий цикл может быть полностью удалён, при условии, что
some_expressionдоказуемо не изменяет глобальное состояние.{ int sum = 0; int ix; for (ix = 0; ix != 10000; ix++) sum += some_expression; }Даже если
sumнакапливается в цикле, эта сумма не используется, поэтому накопление может быть удалено. - Выполнение побочных эффектов в том же порядке, что и в другом компиляторе.
Никогда не безопасно полагаться на порядок вычисления побочных эффектов. Например, вызов функции, подобный этому, может вести себя совершенно по-разному в разных компиляторах:
void func (int, int); int i = 2; func (i++, i++);
Нет гарантии (ни в определении языка C, ни в C++) что инкременты будут вычисляться в каком-либо определённом порядке. Любой инкремент может произойти первым.
funcможет получить аргументы ‘2, 3’, или может получить ‘3, 2’, или даже ‘2, 2’. - Преобразование определённых предупреждений в ошибки по умолчанию.
Некоторые наборы тестов ISO C сообщают об ошибке, когда компилятор не выводит сообщение об ошибке для определённой программы.
ISO C требует сообщения «диагностики» для определённых видов некорректных программ, но предупреждение определено GCC как диагностика. Если GCC выводит предупреждение, но не ошибку, это правильная поддержка ISO C. Если наборы тестов называют это «ошибкой», их следует запускать с опцией компилятора GCC -pedantic-errors, которая преобразует эти предупреждения в ошибки.
Далее: Предупреждения и ошибки, Предыдущее: Неправильное понимание C++, Вверх: Проблемы [Оглавление][Индекс]
© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-8.5.0/gcc/Non-bugs.html