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, который преобразует предупреждения в ошибки.
© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-10.5.0/gcc/Non-bugs.html