11.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в любом другом контексте, логичнее, чтобы они были одинаковыми и в битовых полях.Некоторые производители компьютеров опубликовали стандарты интерфейса двоичных файлов (Application Binary Interface), в которых указывается, что простые битовые поля должны быть беззнаковыми. Однако ошибочно что-либо говорить об этой проблеме в 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, который преобразует эти предупреждения в ошибки.
© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-4.9.4/gcc/Non-bugs.html