C99 - почему false и true определены как 0 и 1, а не как ((bool) 0) и ((bool) 1)? - PullRequest
5 голосов
/ 08 июля 2011

Просто наткнулся на assert, что не удалось, поскольку он сравнил false с возвращаемым типом функции, так как сама функция возвратила bool, и assert проверил не только значение, но и тип возвращаемого значения, чтобы соответствоватьложь, чтобы гарантировать, что бул возвращается.Теперь проблема в том, что C99 определяет bool как _Bool, а _Bool даже не обязательно имеет тот же размер, что и int (на самом деле, по моему опыту, на большинстве платформ в настоящее время он часто имеет тот же размер, что и unsigned char), не говоря уже о том, чтобы быть тем же самымtype (что на самом деле невозможно, так как _Bool является встроенным типом языка в C99), но определяет false и true как 0 и 1 без каких-либо определений типов и препроцессоров без преобразования типов, по умолчанию используется значение int.Если C99 вместо этого определит false и true как ((bool) 0) и ((bool) 1), они всегда будут иметь тип bool, независимо от того, как определен _Bool.Так есть ли веская причина, чтобы они всегда определялись как целые, даже если bool не является целым на этой платформе или это просто ошибка в языке, которую следует исправить с помощью C1x?

Ответы [ 4 ]

8 голосов
/ 08 июля 2011

false и true определены как целочисленные константы 0 и 1 соответственно, потому что это именно то, что стандарт C99 указывает в разделе 7.16 :

Оставшиеся три макроса подходят для использования в #, если директивы предварительной обработки. Oни есть

правда

, который расширяется до целочисленной константы 1,

ложь

, который расширяется до целочисленной константы 0, и

РЕДАКТИРОВАТЬ : как показывают приведенные ниже комментарии, кажется, что я немного неверно истолковал вопрос, и я должен был указать причину, по которой стандарт определяет его так. Одна из причин, по которой я могу придумать, заключается в том, что true и false должны использоваться в директивах предварительной обработки #if (как упоминается в цитате из стандарта).

Причина, по которой ((bool) 0) или ((bool) 1) не будет работать в #if директивах предварительной обработки, заключается в том, что стандарт не допускает этого. В разделе 6.10.1 написано:

Выражение, управляющее условным включением, должно быть выражением целочисленной константы за исключением того, что: он не должен содержать бросок;

4 голосов
/ 08 июля 2011

Помимо других упомянутых выше причин, поскольку _Bool становится int в любом случае, как только вы с ним что-то делаете.

Например, какой тип (_Bool)0 & (_Bool)1?Вы можете подумать, что выражение имеет тип _Bool, но фактически §6.5.10 определяет семантику &:

... Обычные арифметические преобразования выполняются над операндами ...

«обычные арифметические преобразования» имеет очень специфическое значение в стандарте C.Он определен в §6.3.1.8 и включает в себя следующее:

... целочисленные преобразования выполняются для обоих операндов ...

"целочисленные преобразования"также является определенным термином из §6.3.1.1:

Если int может представлять все значения исходного типа, значение преобразуется в int;в противном случае он конвертируется в беззнаковое целое.Они называются целочисленными продвижениями. 48) Все остальные типы неизменяются целочисленными продвижениями.

Хотя в стандарте C существуют более узкие типы, чем int, они автоматически расширяются до intпочти любое выражение.Вместе с тем, что результат логических операций имеет тип int, это делает int естественным выбором для типа этих литералов.

2 голосов
/ 08 июля 2011

Во-первых, хотя _Bool не может быть int, требуется, чтобы _Bool мог принимать значения 0 и 1, поэтому с расширением true и false до 1 и 0 все в порядке.

C99 §6.2.5 / 2 : Объект, объявленный как тип _Bool, достаточно велик для хранения значений 0 и 1.

Также дляДля обратной совместимости true и false целесообразно составить int с, поскольку все логические операторы возвращают int.

C99 §6.5.3.3 / 5 : Результат оператора логического отрицания ! равен 0, если значение его операнда сравнивается с неравным 0, 1, если значение его операнда сравнивается равным 0. Результат имеет тип int.Выражение !E эквивалентно (0==E).

C99 §6.5.8 / 6 : Каждый из операторов < (меньше чем), > (больше чем), <= (меньше или равно) и >= (больше или равно) должны давать 1, если указанное отношение истинно, и 0, если оно ложно. 90) Результатимеет тип int.

C99 §6.5.9 / 3 : операторы == (равно) и != (не равно) аналогичны операторам отношенияза исключением их более низкого приоритета. 91) Каждый из операторов выдает 1, если указанное отношение истинно, и 0, если оно ложно.Результат имеет тип int.Для любой пары операндов верно только одно из отношений.

C99 §6.5.13 / 3 : Оператор && должен выдавать 1, если оба его операнда сравниваются неравнозначно0;в противном случае он возвращает 0. Результат имеет тип int.

C99 §6.5.14 / 3 : оператор || должен выдавать 1, если один из его операндов сравнивается с неравным0;в противном случае он возвращает 0. Результат имеет тип int.

И, наконец, как упоминалось @ Сандер Де Дайкер , определены стандартные true и falseрасширен таким образом (C99 §7.16 / 3).

1 голос
/ 08 июля 2011

Все остальные ответы пытаются использовать стандарт, чтобы обосновать, почему стандарт определяет вещи определенным образом, что я считаю неудовлетворительным.Стандарт определяет не только типы, но также операторы и препроцессор, поэтому, если C99 вводил логический тип, почему бы не изменить все логические операторы для оценки на значения этого типа и расширить препроцессор для поддержки логических типов?

Для этого можно было бы, но сложнее, необходимо.Разработчикам стандартов и авторам компиляторов было гораздо проще вносить только минимально необходимые изменения, чтобы добавить в язык новый логический тип.Поскольку все логические операции по-прежнему оцениваются как тип int, все компиляторы до C99 могут быть обновлены для поддержки C99 без необходимости изменять свой код оценки типа для всех основных операторов, и разработчики стандартов могут быть более уверены вновая логическая функция не случайно внесла несоответствия в те части стандарта, которые раньше были хорошими.Все, что им нужно было сделать, это убедиться, что «обычные арифметические преобразования» применены к _Bool, а затем все остальное гарантированно сработает.

Это не техническая причина.Это практично.

...