C标准是否明确指出真值为0或1?

我们知道任何不等于0数字在C中都被视为true ,所以我们可以这样写:

 int a = 16; while (a--) printf("%d\n", a); // prints numbers from 15 to 0 

然而,我想知道在C中是否将true / false定义为1/0,所以我尝试了下面的代码:

 printf("True = %d, False = %d\n", (0 == 0), (0 != 0)); // prints: True = 1, False = 0 

C标准是否明确地将真假的真值分别表示为10

C标准是否明确地将真假的真值分别表示为01

C标准在stdbool.h定义了truefalse作为macros,分别扩展到10

C11-§7.18:

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

 true 

其展开为整数常数1

 false 

扩展到整数常数0 […]

关于运算符==!=

C11-§6.5.9/ 3:

== (等于)和!= (不等于)运算符类似于关系运算符,但它们的优先级较低。 108)如果指定的关系为真,则每个运算符产生1如果为假,则每个运算符产生0 。 结果有inttypes。 对于任何一对操作数,其中的一个关系是正确的。

在C11中没有明确指出。 所有语言级别的操作都将返回1,并且接受任何非零值,包括NaN为真。

  • 如果你关心_Bool ,那么true必须是1,因为标准只要求它保持0和1.(§6.2.5/ 2)。
  • 同样在<stdbool.h> ,macrostrue扩展为1 (§7.18/ 3)
  • ==!=<><=>=返回0或1(§6.5.8/ 6,§6.5.9/ 3)。
  • !&&|| 返回0或1(§6.5.3.3/ 5,§6.5.13/ 3,§6.5.14/ 3)
  • defined扩展为0或1(§6.10.1/ 1)

但是,所有标准库函数 (例如,第7.4.1 / 1节,第7.17.5.1 / 3节,第7.30.2.1 / 1节,第7.30.2.2.1 / 4节)都只是说“非零”。


§6.2.5/ 2 :声明为_Booltypes的对象足够大以存储值0和1。

§6.5.5.3/ 5 :逻辑否定运算符的结果! 如果其操作数的值不等于0,则其值为0,如果其操作数的值等于0,则为1。

§6.5.8/ 6 :如果指定的关系是< (小于), > (大于), <= (小于或等于)和>= (大于或等于)是真的,如果是假的,则为0。 107)…

§6.5.9/ 3== (等于)和!= (不等于)运算符与关系运算符类似,只是它们的优先级较低.108)如果指定的关系为真,则每个运算符产生1;如果它是假的,则为0。 …

§6.5.13/ 3 :如果两个操作数不等于0, &&操作符应该产生1; …

§6.5.14/ 3|| 如果其任一操作数比较不等于0,则运算符应产生1; …

§6.10.1/ 1 :…它可以包含一个表单defined identifierdefined identifier一元运算符expression式,如果…

§7.4.1(字符分类函数)/ 1 :本小节中的函数返回非零(真),当且仅当…

§7.18/ 3 :其余的三个macros适用于#if预处理指令。 它们是 – true – 扩展到整数常量1,…

§7.17.5.1/ 3 :当且仅当对象的操作是无锁的, atomic_is_lock_freegenerics函数返回非零(真)。 …

§7.30.2.1(宽字符分类函数)/ 1 :本小节中的函数返回非零(真),当且仅当…

§7.30.2.2.1/ 4iswctype函数返回非零(true)当且仅当…

当在C中处理布尔值(我指的是true / false值而不是特定的C bool/_Booltypes)时需要注意标准的两个方面。

第一个与expression式的结果有关,可以在C11 6.5 Expressions (例如关系和相等运算符)的各个部分find。 底线是,只要expression式生成一个布尔值,它…

…如果指定的关系为真,则返回1,否则返回0。 结果有inttypes。

所以,是的,任何布尔生成expression式的结果将是一个为真,或为零为零。 这与您在stdbool.h中find的内容相匹配,其中标准macrostruefalse的定义方式相同。

但请记住,遵循“你所发的是保守的,你所接受的是自由的”的稳健性原则,对布尔环境中的整数的解释是比较宽松的。

再次,从6.5各个部分,你会看到像这样的语言:

|| 如果其任一操作数比较不等于0,则运算符应产生1 ; 否则,结果为0 ,结果为int型。

从那个(和其他部分),很明显,零被认为是错误的, 任何其他的值是真实的。


另外,规定用于布尔生成和解释的值的语言也出现在C99和C89中,所以它们已经存在了相当长的一段时间。 即使是K&R(ANSI-C第二版第一版)也指定了文本片段,例如:

关系expression式如i > j和由&&||连接的逻辑expression式 被定义为具有值1如果为真,则为0

ifwhilefor等的testing部分中,“true”意味着“非零”。

&&运算符…如果两个操作数都不等于零,则返回1,否则返回0。

|| 如果操作数比较不等于零,则返回1;否则返回0。

stdbool.h的macros也会出现在C99中,但是不会出现在C89或K&R中,因为该头文件在该点不存在。

你混合了很多不同的东西:控制语句,运算符和布尔types。 每个人都有自己的规则。

控制语句就像例如if语句,C11 6.4.8.1:

在这两种forms中,如果expression式不等于0,则执行第一个子语句。

while for等有相同的规则。 这与“真”或“假”无关。

对于假定产生布尔结果的运算符,实际上它们产生的值为1或0。例如,相等运算符C11 6.5.9:

如果指定的关系为真,则每个运算符产生1,如果为假,则产生0

所有这些都是因为C直到1999年才有布尔型,即使得到了一个,上面的规则也没有改变。 因此,与大多数语言和运算符产生布尔types(比如C ++和Java)的大多数其他编程语言不同,它们只是产生一个int值,其值为零或不为零。 例如, sizeof(1==1)将在C中给出4,而在C ++中为1。

C中的实际布尔types被命名为_Bool并且需要一个现代编译器。 头文件stdbool.h定义了macrosbooltruefalse ,分别扩展为_Bool10 (与C ++兼容)。


然而,将控制语句和操作符看作是实际需要/产生布尔types的编程习惯是很好的。 某些编码标准如MISRA-C推荐了这样的实践。 那是:

if(ptr == NULL)而不是if(ptr)

if((data & mask) != 0)而不是if(data & mask)

这种风格的目的是通过静态分析工具来增加types安全性,从而减less错误。 可以说,这种风格只有在使用静态分析仪时才有意义。 尽pipe在某些情况下会导致更具可读性的自我logging代码

 if(c == '\0') 

好,意图很清楚,代码是自我logging的。

 if(c) 

坏。 可能意味着什么,我们必须去寻找types的c来理解代码。 它是一个整数,一个指针还是一个字符?

我用很多语言编程。 我已经看到真正的1或-1取决于语言。 真正的1背后的逻辑是有一点是0或1。真正的-1是背后的逻辑! 运营商是一个补充。 它把所有的1改为0,所有的0改为1。 所以,对于一个int,!0 = -1和!( – 1)= 0。这已经让我绊倒了足够的,我不比较东西是==真,而是比较它是!=假。 这样,我的编程风格适用于每种语言。 所以我的答案是不担心,但程序,使您的代码正确的方式。

这个答案需要更仔细一点。

在C ++中的实际定义是,任何不是0被视为true。 为什么这是相关的? 因为C ++并不知道我们如何思考整数是什么 – 我们创造了这个意义,它所拥有的只是shell和规则的意思。 它知道哪些位是通过哪些构成整数。

1作为一个整数松散地表示为比特,例如8位有符号整数作为0000 0001.很多时候,我们在视觉上看到的是一个谎言,-1是一个更常见的方式来表示它,因为签名的性质'整数'。 1真的不能代表真实,为什么? 因为它不是操作1111 1110.这是一个布尔真正的主要问题。 当我们谈论一个布尔值时,它只是1位 – 它非常简单,0是错误的,1是真的。 所有的逻辑操作都是微不足道的。 这就是为什么“-1”应该被指定为“真”的整数(有符号)。 1111 1111 NOT'ed变成0000 0000 – 逻辑成立,我们很好。 无符号整数有点棘手,过去更常用 – 其中1表示为真,因为很容易暗示“任何不为0的逻辑”。

这是解释。 我说这里接受的答案是错误的 – 在C / C ++定义中没有明确的定义。 一个布尔值是一个布尔值,你可以把一个整数当作一个布尔值,但是输出是一个整数,事实上,所做的操作是按位进行的。

这是因为printf语句中的关系操作符。

运算符==和运算符!=

由于(0 == 0)成立,所以给出值1

(0 != 0)不成立,所以给出一个值0