13.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), которые указывают, что обычные битовые поля должны быть беззнаковыми. Однако ошибочно что-либо говорить об этой проблеме в 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-6.5.0/gcc/Non-bugs.html