14.8 Некоторые изменения, которые мы не хотим вносить
В этом разделе перечислены изменения, которые люди часто запрашивают, но которые мы не вносим, потому что считаем, что GCC будет лучше без них.
- Проверка количества и типов аргументов функции со старой определением без прототипа.
Такая функция будет работать только в некоторых случаях — только для вызовов, которые появляются в том же файле, что и вызываемая функция, после определения. Единственный способ надежно проверить все вызовы — добавить прототип функции. Но добавление прототипа исключает мотивацию для этой функции. Поэтому функция не стоит того.
- Предупреждение об использовании выражения, тип которого со знаком, в качестве сдвига.
Операнды сдвига, вероятно, чаще имеют тип со знаком, чем без знака. Предупреждение об этом вызовет больше раздражения, чем пользы.
- Предупреждение об присваивании значения со знаком беззнаковому переменной.
Такие присваивания должны быть очень распространены; предупреждение об них вызовет больше раздражения, чем пользы.
- Предупреждение, когда значение функции, отличной от void, игнорируется.
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-12.2.0/gcc/Non-bugs.html