13.8 Некоторые изменения, которые мы не хотим вносить
В этом разделе перечислены изменения, которые люди часто запрашивают, но которые мы не вносим, потому что считаем, что GCC лучше без них.
- Проверка количества и типов аргументов функции со старым определением и без прототипа.
Такая функция будет работать только в отдельных случаях — только для вызовов, которые появляются в том же файле, что и вызываемая функция, после определения. Единственный способ надежно проверить все вызовы — добавить прототип для функции. Но добавление прототипа устраняет мотивацию для этой функции. Поэтому данная функция не стоит затраченных усилий.
- Предупреждение об использовании выражения, тип которого имеет знаковое представление, в качестве сдвига.
Операнды сдвига чаще имеют знаковое представление, чем беззнаковое. Предупреждение об этом вызовет гораздо больше неудобств, чем пользы.
- Предупреждение об присваивании знакового значения беззнаковой переменной.
Такие присваивания должны быть очень распространены; предупреждение об них вызовет больше неудобств, чем пользы.
- Предупреждение, когда значение функции, отличное от void, игнорируется.
C содержит много стандартных функций, которые возвращают значение, которое большинство программ предпочитают игнорировать. Яркий пример —
printf. Предупреждение об этой практике только заставит защищенного программиста загромождать программы десятками приведений кvoid. Такие приведения необходимы так часто, что они становятся визуальным шумом. Написание этих приведений становится настолько автоматическим, что они больше не передают полезной информации о намерениях программиста. Для функций, где значение возврата никогда не должно игнорироваться, используйте атрибут функцииwarn_unused_result(см. Атрибуты функций). - Установка -fshort-enums в качестве значения по умолчанию.
Это приведет к несовместимости структуры хранения с большинством других компиляторов C. И это не кажется очень важным, учитывая, что того же результата можно добиться другими способами. Случай, когда это имеет наибольшее значение, — это когда перечисление с объектом находится внутри структуры, и в этом случае можно явно указать ширину поля.
- Установка по умолчанию типа bit-fields на unsigned на определенных машинах, где «стандарт ABI» диктует это.
Стандарт ISO C оставляет за реализацией выбор, будет ли поле bit-field, объявленное как
int, со знаком или без знака. Это фактически создает два альтернативных диалекта C.Компилятор GNU C поддерживает оба диалекта; вы можете указать диалект со знаком с помощью -fsigned-bitfields, а диалект без знака с помощью -funsigned-bitfields. Однако это оставляет открытым вопрос о том, какой диалект использовать по умолчанию.
В настоящее время предпочтительный диалект делает поля bit-fields со знаком, потому что это проще. Поскольку
intэквивалентноsigned intв любом другом контексте, для них наиболее чисто использовать один и тот же тип в bit-fields.Некоторые производители компьютеров опубликовали стандарты интерфейса двоичных приложений, в которых указывается, что поля bit-fields по умолчанию должны быть без знака. Однако ошибка в том, чтобы что-либо говорить об этой проблеме в ABI. Это связано с тем, что обработка обычных bit-fields отличает два диалекта C. Оба диалекта имеют смысл на любом типе машины. Файл объектного кода, скомпилированный с bit-fields со знаком или без знака, не имеет значения для других объектных файлов, даже если они обращаются к тем же bit-fields в одних и тех же структурах данных.
Программа написана в одном из этих двух диалектов. Программа имеет шанс работать на большинстве машин, если она скомпилирована с правильным диалектом. Вряд ли она будет работать вообще, если скомпилирована с неправильным диалектом.
Многие пользователи ценят компилятор GNU C за то, что он обеспечивает единообразную среду на разных машинах. Эти пользователи столкнутся с неудобствами, если компилятор будет по-разному обрабатывать обычные поля bit-fields на определенных машинах.
Иногда пользователи пишут программы, предназначенные только для определенного типа машин. В таких случаях пользователи могли бы извлечь выгоду, если бы компилятор GNU C поддерживал по умолчанию тот же диалект, что и другие компиляторы на этой машине. Но такие приложения редки. И пользователи, пишущие программу для работы на нескольких типах машин, не могут извлечь никакой выгоды из этого вида совместимости.
Вот почему GCC будет и впредь обрабатывать обычные bit-fields одинаково на всех типах машин (по умолчанию).
Есть некоторые аргументы в пользу установки по умолчанию unsigned для bit-fields на всех машинах. Например, если это станет универсальным фактическим стандартом, было бы логично, что GCC будет соответствовать ему. Это стоит рассмотреть в будущем.
(Конечно, пользователи, сильно озабоченные переносимостью, должны явно указывать в каждом bit-field, со знаком оно или без знака. Таким образом, они пишут программы, которые имеют одинаковый смысл в обоих диалектах 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-9.5.0/gcc/Non-bugs.html