Просто наткнулся на утверждение, которое не удалось, поскольку оно сравнивало false с типом возврата функции, поскольку сама функция вернула bool, а assert проверил не только значение, но и тип возвращаемого значения на соответствие ложному, чтобы гарантировать, что возвращается bool. Теперь проблема в том, что C99 определяет bool как _Bool и _Bool даже не обязательно того же размера, что и int (на самом деле, по моему опыту, на большинстве платформ в настоящее время он часто имеет такой же размер, как unsigned char), не говоря уже о том, чтобы быть таким же type (что на самом деле невозможно, поскольку _Bool является встроенным типом языка в C99), но определяет false и true как 0 и 1 без какого-либо преобразования типов, а определения препроцессора без преобразования типа по умолчанию будут иметь значение int. Если бы C99 вместо этого определил false и true как ((bool) 0) и ((bool) 1), они всегда были бы типа bool, независимо от того, как определяется _Bool. Итак, есть ли веская причина, чтобы они всегда определялись как int, даже если bool не является int на этой платформе или это просто ошибка языка, которую следует исправить с помощью C1x?
C99 - почему ложь и истина определены как 0 и 1, а не как ((bool) 0) и ((bool) 1)?
Ответы (4)
false
и true
определены как целочисленные константы 0
и 1
соответственно, потому что это именно то, что стандарт C99 определяет в разделе 7.16:
‹СНИП>
Остальные три макроса подходят для использования в директивах предварительной обработки #if. Они есть
верно
который расширяется до целочисленной константы 1,
ложь
который расширяется до целочисленной константы 0, и
‹СНИП>
ИЗМЕНИТЬ: как показывают комментарии ниже, кажется, я немного неверно истолковал вопрос и должен был указать причину, по которой стандарт определяет это именно так. Одна из причин, по которой я могу думать, заключается в том, что true
и false
должны использоваться в #if
директивах предварительной обработки (как упоминается в цитате из стандарта).
Причина, по которой ((bool) 0)
или ((bool) 1)
не работают в #if
директивах предварительной обработки, заключается в том, что стандарт не допускает этого. В разделе 6.10.1 говорится:
Выражение, управляющее условным включением, должно быть целочисленным постоянным выражением, за исключением того, что: оно не должно содержать приведения;
_Bool
, заключается в том, что они должны использоваться в директивах предварительной обработки #if
, как упоминается в приведенной выше цитате.
- person Sander De Dycker; 08.07.2011
(bool)+1
и (bool)+0
будут действительны в #if
, не так ли? bool
будет заменен на _Bool
, который затем будет заменен на 0
.
- person R.. GitHub STOP HELPING ICE; 01.10.2011
true
и false
именно так?
- person Sander De Dycker; 01.10.2011
sizeof true
и sizeof false
, я думаю, это было бы просто глупо ...
- person R.. GitHub STOP HELPING ICE; 01.10.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
естественным выбором для типа этих литералов.
_Bool
, и что, если бы у вызовов функций были побочные эффекты, которые вы не хотели бы терять из-за короткого замыкания?
- person jamesdlin; 09.07.2011
Во-первых, хотя _Bool
может не быть int
, требуется, чтобы _Bool
мог принимать значения 0 и 1, поэтому расширение true
и false
до 1 и 0 нормально.
C99 §6.2.5 / 2: объект, объявленный как тип _Bool, достаточно велик, чтобы хранить значения 0 и 1.
Кроме того, для обратной совместимости true
и false
разумно быть int
s, потому что все логические операторы возвращают 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
.
И, наконец, как @ Sander De Dycker упомянул, что стандартные, определенные true
и false
, должны быть расширены таким образом (C99 §7.16 / 3).
Все остальные ответы пытаются использовать стандарт, чтобы оправдать, почему стандарт определяет вещи определенным образом, что я считаю неудовлетворительным. Стандарт определяет не только типы, но также операторы и препроцессор, поэтому, если C99 вводил логический тип, почему бы не изменить все логические операторы, чтобы вычислить значение этого типа, и не расширить препроцессор для поддержки логических типов?
Сделать это можно, но нужно сложнее. Разработчикам стандартов и составителям компиляторов было намного проще внести только минимально необходимые изменения, чтобы добавить в язык новый логический тип. Поскольку все логические операции по-прежнему оцениваются как тип int
, все компиляторы до C99 могут быть обновлены для поддержки C99 без необходимости изменять свой код оценки типа для всех основных операторов, а разработчики стандартов могут быть более уверены в том, что новый Логическая функция не случайно внесла несоответствия в части стандарта, которые раньше были хороши. Все, что им нужно было сделать, это убедиться, что к _Bool
применяются «обычные арифметические преобразования», и тогда все остальное будет гарантированно работать.
Это не техническая причина. Это практично.