C99 – 为什么假和真的定义为0和1而不是((bool)0)和((bool)1)?
偶然发现了一个失败的断言,因为它将false与函数的返回类型进行比较,因为函数本身返回了一个bool并且断言不仅检查了值,而且还检查了返回值的类型以匹配false,保证,返回一个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,或者这只是语言中的一个bug,应该用C1x修复?
false
和true
分别定义为整数常量0
和1
,因为这正是C99标准在7.16节中指定的内容:
其余三个宏适用于#if预处理指令。 他们是
真正
它扩展为整数常量1,
假
它扩展为整数常量0,和
编辑 :正如下面的评论所示,似乎我略微误解了这个问题,我应该提供标准指定它的原因。 我能想到的一个原因是,在#if
预处理指令中可以使用true
和false
(如标准提及的引用)。
原因((bool) 0)
或((bool) 1)
在#if
预处理指令中不起作用,是因为标准不允许它。 在6.10.1节中,它说:
控制条件包含的表达式应为整数常量表达式,除了:它不应包含强制转换;
除了已经提到的其他原因之外,因为只要你用它做任何事情, _Bool
就会成为一个int
。
例如, (_Bool)0 & (_Bool)1
_ (_Bool)0 & (_Bool)1
_ (_Bool)0 & (_Bool)1
的类型是什么? 您可能认为表达式的类型为_Bool
,但实际上§6.5.10定义了&
的语义:
…通常的算术转换是在操作数上执行的……
“通常的算术转换”在C标准中具有非常特殊的含义。 它在§6.3.1.8中定义,包括以下内容:
…在两个操作数上执行整数提升…
“整数促销”也是一个定义的术语,来自§6.3.1.1:
如果int可以表示原始类型的所有值,则该值将转换为int; 否则,它将转换为unsigned int。 这些被称为整数促销.48)所有其他类型由整数促销不变。
虽然C标准中存在比int
更窄的类型,但它们几乎在任何表达式中都自动扩展为int
。 与布尔运算的结果类型为int
的事实一起,这使得int
成为这些文字类型的自然选择。
首先,尽管_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;如果其操作数的值比较等于0则为1.结果的类型为int
。 表达式!E
等价于(0==E)
。C99§6.5.8/ 6 :如果指定的话,每个运算符
<
(小于),>
(大于),<=
(小于或等于)和>=
(大于或等于)将产生1 relation为true,如果为false则为0。 90)结果的类型为int
。C99§6.5.9/ 3 :
==
(等于)和!=
(不等于)运算符类似于关系运算符,除了它们的优先级较低。 91)如果指定的关系为真,则每个运算符产生1,如果为假,则产生0。 结果是int
类型。 对于任何一对操作数,其中一个关系是正确的。C99§6.5.13/ 3 :如果
&&
运算符的两个操作数都不等于0,则它将产生1; 否则,它产生0.结果类型为int
。C99§6.5.14/ 3 :
||
如果操作数的任何一个比较不等于0,则运算符应该为1; 否则,它产生0.结果类型为int
。
最后,正如@Sander De Dycker所提到的,标准定义的false
都是这样扩展的(C99§7.16/ 3)。
所有其他答案都试图使用标准来certificate标准为什么以某种方式定义事物,我觉得这种方法并不令人满意。 标准不仅定义了类型,还定义了运算符和预处理器,因此如果C99引入了布尔类型,为什么不更改所有布尔运算符以评估该类型的值并扩展预处理器以支持布尔类型?
这样做是可能的,但必要的更复杂。 标准编写者和编译器编写者只需要进行最少的必要更改即可为语言添加新的布尔类型。 由于所有布尔运算仍然评估为int
类型,因此可以更新所有C99之前的编译器以支持C99,而无需为所有基本运算符更改其类型评估代码,并且标准编写者可以更自信地使用新的布尔特征没有意外地将不一致性引入先前已经很好的标准部分。 他们所需要做的就是确保将“通常的算术转换”应用于_Bool
,然后保证其他一切都能正常工作。
这不是技术原因。 这是一个实用的。