C99 - 为什么假和真的定义为0和1而不是((bool)0)和((bool)1)?

时间:2011-07-08 16:02:57

标签: c language-design c99 boolean

偶然发现了一个失败的断言,因为它将false与函数的返回类型进行比较,因为函数本身返回了一个bool并且断言不仅检查了值,还检查了返回值的类型以匹配一个假,保证,返回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修复?

4 个答案:

答案 0 :(得分:8)

falsetrue分别定义为整数常量01,因为这正是C99标准在 7.16 :

  

< SNIP>

     

其余三个宏适用于 #if 预处理指令。他们   是

     

<强>真

     

扩展为整数常量1,

     

<强>假

     

扩展为整数常量0和

     

&LT; SNIP&gt;

编辑:正如下面的评论所示,似乎我有点误解了这个问题,我应该提供标准指定它的原因。我能想到的一个原因是,truefalse应该可以在#if预处理指令中使用(如标准提及的引用)。

((bool) 0)((bool) 1)#if预处理指令中不起作用的原因是因为标准不允许它。在 6.10.1 部分中,它说:

  

控制条件包含的表达式应为整数常量表达式   除了:它不应包含演员表;

答案 1 :(得分:4)

除了已经提到的其他原因之外,因为只要你做了几乎任何事情,_Bool就会成为int

例如,(_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成为这些文字类型的自然选择。

答案 2 :(得分:2)

首先,虽然_Bool可能不是int,但要求_Bool可以接受值0和1,因此展开true和{{1} }到1和0都没问题。

  

C99§6.2.5/ 2 :声明为_Bool类型的对象足以存储值0和1。

此外,为了向后兼容,falsetrue合理为false,因为所有逻辑运算符都返回int

  

C99§6.5.3.3/ 5 :如果操作数的值不等于0,则逻辑否定运算符int的结果为0,如果其操作数的值为1则为1比较等于0.结果类型为!。表达式int相当于!E

     

C99§6.5.8/ 6 :每个运营商(0==E)(小于),<(大于),>(小于或者等于),<=(大于或等于)如果指定的关系为真,则产生1,如果为假,则产生0。 90)结果的类型为{{1 }}

     

C99§6.5.9/ 3 >=(等于)和int(不等于)运算符类似于关系运算符,除了它们较低优先级。 91)如果指定的关系为真,则每个运算符产生1,如果为假,则产生0。结果的类型为==。对于任何一对操作数,其中一个关系是正确的。

     

C99§6.5.13/ 3 :如果!=运算符的两个操作数均不等于0,则int运算符将产生1;否则,它产生0.结果的类型为&&

     

C99§6.5.14/ 3 int运算符如果其任一操作数的比较不等于0,则应生成1;否则,它产生0.结果的类型为||

最后,正如@Sander De Dycker提到的那样,标准定义inttrue会像那样扩展(C99§7.16/ 3)。

答案 3 :(得分:1)

所有其他答案都试图使用标准来证明标准为什么以某种方式定义事物,我发现这种方式并不令人满意。标准不仅定义了类型,还定义了运算符和预处理器,因此如果C99引入了布尔类型,为什么不更改所有布尔运算符以评估该类型的值并扩展预处理器以支持布尔类型? / p>

这样做是可能的,但必要的更复杂。标准编写者和编译器编写者只需要进行最少的必要更改就可以更容易地为语言添加新的布尔类型。由于所有布尔运算仍然评估为int类型,因此可以更新所有C99前编译器以支持C99,而无需为所有基本运算符更改其类型评估代码,标准编写器可以更多确信新的布尔特征没有意外地引入先前已经很好的标准部分的不一致性。他们所需要做的就是确保将“通常的算术转换”应用于_Bool,然后保证其他所有内容都能正常工作。

这不是技术原因。这是一个实用的。