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-5.5.0/gcc/Non-bugs.html