为什么0为假?


115

这个问题听起来很愚蠢,但是为什么大多数编程语言都将0求值false和其他任何[整数]值true呢?

字符串比较

由于问题似乎太简单了,所以我将对自己进行一些解释:首先,对于任何程序员来说,这似乎都是显而易见的,但是为什么没有编程语言呢?实际上可能是,但是没有我用了-在哪0求和true,所有其他[整数]值都在false?这句话似乎是随机的,但我举了一些例子,可能是个好主意。首先,让我们以字符串三向比较为例,以C strcmp为例:任何以C为第一语言的程序员都可能会编写以下代码:

if (strcmp(str1, str2)) { // Do something... }

由于strcmp返回的0结果是评估false字符串何时相等,因此初阶程序员尝试执行的操作很失败,而且他通常一开始并不理解为什么。曾0评估,以true代替,这个功能可能已在其最简单的表达式中使用-上面的一员-平等的比较时,以及适当的检查-1,并1在需要时将已只是做。bool在大多数情况下,我们会认为返回类型是(在我们看来)。

此外,我们引入一个新的类型,sign即只需要值-101。那可能很方便。想象一下,在C ++中有一个太空飞船运算符,我们想要它std::string(好吧,已经有compare函数了,但是太空飞船运算符更有趣)。该声明当前将是以下声明:

sign operator<=>(const std::string& lhs, const std::string& rhs);

已经0被评估为true,飞船运营商甚至不存在的,我们可以宣称operator==这种方式:

sign operator==(const std::string& lhs, const std::string& rhs);

operator==将立即处理三向比较,并且仍然可以用于执行以下检查,同时在需要时仍能够检查哪个字符串在字典上优于另一个字符串:

if (str1 == str2) { // Do something... }

旧错误处理

现在我们有了例外,因此本部分仅适用于不存在此类旧语言的旧语言(例如C)。如果我们看一下C的标准库(还有POSIX),我们可以肯定地看到maaaaany函数0在成功时返回,否则返回任何整数。我可悲地看到有些人做这种事情:

#define TRUE 0
// ...
if (some_function() == TRUE)
{
    // Here, TRUE would mean success...
    // Do something
}

如果我们考虑编程中的想法,我们通常具有以下推理模式:

Do something
Did it work?
Yes ->
    That's ok, one case to handle
No ->
    Why? Many cases to handle

如果我们再考虑一下,将唯一的中性值0放到yes(这就是C函数的工作方式)上是有意义的,而所有其他值都可以用来解决no。然而,在我所知道的所有编程语言(可能除了一些实验esotheric语言),即yes计算为falseif状态,而所有的no情况下,计算结果为true。在许多情况下,“有效”代表一种情况,而“无效”则代表许多可能的原因。如果我们以这种方式思考,那么0对评估true和其余评估false将更有意义。

结论

我的结论基本上是我原来的问题:为什么我们的设计语言;这里0false和其它值true,同时帐户我举几个例子上面,也许一些我没想到的?

后续行动:很高兴看到有很多答案,其中有很多想法,并且有很多可能的原因。我喜欢您似乎对此充满热情。我本来是出于无聊的问题而提出这个问题的,但是由于您似乎太热情了,所以我决定进一步探讨一下Math.SE上布尔选择0和1的理由:)


32
strcmp()不是true或false的好例子,因为它返回3个不同的值。当您开始使用shell时,您会感到惊讶,其中0表示true,其他表示false。
ott--

52
@ ott--:在Unix shell中,0表示成功,非零表示失败 -与“ true”和“ false”不太一样。
基思·汤普森

14
@KeithThompson:在Bash(和其他shell)中,“成功”和“失败”实际上与“ true”和“ false”相同。例如,考虑以下语句if true ; then ... ; fi:where true是一个返回零的命令,该命令告诉ifrun ...
鲁阿赫

13
硬件中没有布尔值,只有二进制数,并且在大多数历史ISA中,在所有条件分支指令中,非零数都被视为“ true”(除非它们使用标志代替)。因此,低级语言绝对必须遵循基本的硬件属性。
SK-logic

2
@MasonWheeler具有布尔类型并不表示任何内容。例如python 确实具有bool类型,但是比较/ if条件等可以具有任何返回值。
巴库里

Answers:


98

0false因为它们在普通半环中都是零元素。即使它们是不同的数据类型,由于它们属于同构代数结构,因此在它们之间进行转换也很直观。

  • 0是加法的标识,乘法的零。这对于整数和有理数是正确的,但对于 IEEE-754浮点数则不是0.0 * NaN = NaN0.0 * Infinity = NaN

  • false是布尔异或(⊻)的标识,并且是布尔(∧)的标识。如果布尔值表示为{0,1}(以2为模的整数集),则可以将⊻视为没有进位的加法,并将∧视为乘法。

  • ""[]是串联的标识,但是有几个操作将它们视为零。重复是一个,但重复和串联不会分布,因此这些操作不会形成半环。

这种隐式转换在小型程序中很有用,但在大型程序中可能会使程序难以推理。语言设计中的众多折衷方案之一。


1
很高兴您提到列表。(顺便说一句,nil空列表[]falseCommon Lisp中的值都是一样;是否有合并来自不同数据类型的身份的趋势?)您仍然必须解释为什么将false作为加法身份而将true视为乘法身份是很自然的而不是相反。不可能将其视为truefor的标识AND和零OR吗?
乔治

3
+1表示相似的身份。最后,答案不仅仅归结为“常规,应对”。
l0b0

5
+1给出具体的细节和非常古老的数学在此一直沿袭和长有道理
吉米·霍法

1
这个答案没有道理。true也是半环的标识和零(布尔值和/或)。appart约定,没有理由考虑false比0更接近0 true
TonioElGringo 2015年

1
@TonioElGringo:true和false之间的区别是XOR和XNOR之间的区别。一个人可以使用AND / XOR来形成同构环,其中true是乘法恒等式,而false是加法恒等,或与OR和XNOR,其中false是乘法恒等式,而true是加法恒等,但是XNOR通常不被视为通用XOR的基本操作方式。
超级猫

74

因为数学有效。

FALSE OR TRUE is TRUE, because 0 | 1 is 1.

... insert many other examples here.

传统上,C程序具有以下条件

if (someFunctionReturningANumber())

而不是

if (someFunctionReturningANumber() != 0)

因为零的概念等同于false是众所周知的。


21
语言的设计是这样的,因为数学很有意义。首先。
罗伯特·哈维

26
@Morwenn,它可以追溯到19世纪和George Boole。人们将False表示为0,将True表示为!0的时间比计算机早。
查尔斯·格兰特

11
如果您仅更改所有定义,以使AND为+且OR为*,我看不出为什么数学不能以其他方式起作用。
尼尔·G

7
确实:数学是双向的,这个问题的答案似乎是纯粹的传统。
Neil G

6
@Robert如果您能在帖子中阐明“数学基础”,那就太好了。
phant0m

38

正如其他人所说,数学是第一位的。这就是为什么0是false和1是的原因true

我们在说什么数学?布尔代数可追溯到1800年代中期,远早于数字计算机的出现。

您也可以说该约定来自命题逻辑,它甚至比布尔代数还早。这是程序员知道并喜欢的许多逻辑结果的形式(false || x等于xtrue && x等于x等)。

基本上,我们是在讨论具有两个元素的集合上的算术。考虑以二进制计数。布尔代数是该概念的起源及其理论基础。诸如C之类的语言约定只是一个简单的应用程序。


2
当然可以。但是将其保持为“标准”方式与通用算术非常吻合(0 + 1 = 1,而不是0 + 1 = 0)。
joshin4colours

2
是的,但是如果您也颠倒了定义,则可能会用+或OR来写AND。
尼尔·G

3
数学不是第一位的。数学认识到0和1构成一个字段,其中AND就像乘法,而OR就像加法。
卡兹(Kaz)

1
@Kaz:但是带有OR和AND的{0,1}不会形成字段。
Giorgio

2
更多的答案和评论都这样说,这让我有些烦恼true = 1。这不是很准确,因为true != 0两者并不完全相同。为什么要避免类似之类的一个原因(并非唯一原因)if(something == true) { ... }
JensG 2013年

26

我认为这与电子学以及布尔代数的“继承性”有关

  • 0= offnegativenofalse
  • 1= onpositiveyestrue

当字符串相等时,strcmp返回0与其实现有关,因为它的实际作用是计算两个字符串之间的“距离”。0也恰好被认为是假的,这只是一个巧合。

成功返回0是有意义的,因为在这种情况下,0表示没有错误,而其他任何数字都将是错误代码。使用任何其他数字来获得成功意义不大,因为您只有一个成功代码,而您可能有多个错误代码。您使用“它起作用了吗?” 如if语句表达式,并说0 = yes更有意义,但该表达式更正确:“是否出错?” 然后您会看到0 = no很有意义。false/true在这里思考实际上并没有任何意义no error code/error code


哈哈,您是第一个明确声明返回错误问题的人。我已经知道我以自己的方式解释它,也可以通过其他方式解释它,但是您是第一个明确表达它的人(在许多答案和评论中)。实际上,我不会说一种或另一种方式没有任何意义,但更多的是两种方式都以不同的方式具有意义:)
Morwenn 2013年

1
实际上,我想说0success/no error是,当其他整数表示错误代码时,这是唯一有意义的事情。在其他情况下,这0也恰好表示false并不重要,因为我们在这里根本不是在谈论真假;)
Svish

我也有同样的想法,所以我就提高了
user60812

1
您关于strcmp()计算距离的观点非常好。如果它被调用,strdiff()if (!strdiff())将是非常合乎逻辑的。
Kevin Cox

“电子学,其中0 =假,1 =真”-即使在电子学中,这也只是一个约定,并不是唯一的约定。我们称其为正逻辑,但是您也可以使用负逻辑,其中正电压表示假,负电压表示真。然后,您用于AND的电路变为OR,或OR变为AND,依此类推。根据De Morgan的法律,所有这些最终都是等效的。有时,为了方便起见,您会发现以负逻辑实现的电子电路的一部分,这时该部分中信号的名称会在信号上方标出一个条形。
Jules '18

18

本文所述,值falsetrue不应与整数0和1混淆,而可以用两个元素的Galois字段(有限字段)的元素标识(请参见此处)。

字段是具有满足特定公理的两个运算的集合。

传统上,符号0和1用于表示字段的加和乘积身份,因为实数也是其身份为数字0和1的字段(但不是有限的)。

加性标识是字段的元素0,因此对于所有x:

x + 0 = 0 + x = x

乘法身份是该字段的元素1,因此对于所有x:

x * 1 = 1 * x = x

两个元素的有限域仅具有这两个元素,即加性恒等式0(或false)和乘法恒等式1(或true)。该字段的两个操作是逻辑XOR(+)和逻辑AND(*)。

注意。如果翻转操作(XOR是乘法,而AND是加法),则乘法不会在加法上分配,并且您将不再有字段。在这种情况下,您没有理由调用两个元素0和1(以任何顺序)。还要注意,您不能选择操作OR而不是XOR:无论您如何将OR / AND解释为加法/乘法,结果结构都不是字段(字段公理要求的并非所有逆元素都存在)。

关于C函数:

  • 许多函数返回一个整数,该整数是错误代码。0表示没有错误。
  • 直观地,该函数strcmp计算两个字符串之间的差。0表示两个字符串之间没有差异,即两个字符串相等。

上面的直观解释可以帮助您记住返回值的解释,但是仅检查库文档甚至更加容易。


1
+1表示如果您任意交换这些,则数学将不再有效。
吉米·霍法

2
翻转:给定一个包含两个元素以及运算符*和+的字段,我们将0标识为True,将1标识为False,将*标识为OR或将+标识为XOR。
尼尔·G

1
您会发现这两个标识都是在同一字段上完成的,并且都与布尔逻辑规则一致。不幸的是,您的注释不正确:)
Neil G

1
如果假设True = 0,且XOR为+,则True必须是XOR的标识。但这不是因为True XOR True = False。除非您在True上重新定义XOR操作,以便True XOR True = True。然后,您的构造当然会工作,因为您刚刚对事物进行了重命名(在任何数学结构中,您始终可以成功进行名称排列并获得同构结构)。在另一方面,如果你让真,假和XOR有其通常的含义,那么真正的XOR真=假和真不能添加剂身份,即真不能为0
乔治

1
@Giorgio:我根据您在最近的评论中的评论纠正了我的观点……
Neil G

13

您应该考虑到替代系统也可以成为可接受的设计决策。

Shells:0退出状态为true,非零为false

已经提到了将0退出状态视为true的shell的示例。

$ ( exit 0 ) && echo "0 is true" || echo "0 is false"
0 is true
$ ( exit 1 ) && echo "1 is true" || echo "1 is false"
1 is false

这里的基本原理是有一种成功的方法,但是有许多失败的方法,因此使用0作为特殊值表示“没有错误”是实用的。

Ruby:0就像其他任何数字一样

在“常规”编程语言中,有一些异常值(例如Ruby)将0视为真实值。

$ irb
irb(main):001:0> 0 ? '0 is true' : '0 is false'
=> "0 is true"

理由是,只有falsenil应该是假的。对于许多Ruby新手来说,这是一个陷阱。但是,在某些情况下,将0视为其他任何数字也很好。

irb(main):002:0> (pos = 'axe' =~ /x/) ? "Found x at position #{pos}" : "x not found"
=> "Found x at position 1"
irb(main):003:0> (pos = 'xyz' =~ /x/) ? "Found x at position #{pos}" : "x not found"
=> "Found x at position 0"
irb(main):004:0> (pos = 'abc' =~ /x/) ? "Found x at position #{pos}" : "x not found"
=> "x not found"

但是,这样的系统只能以能够将布尔值作为数字的单独类型区分的语言工作。在计算的早期,使用汇编语言或原始机器语言的程序员没有这种奢侈。将0视为“空白”状态,并在代码检测到发生了某些事情时将位设置为1,这很自然。通过扩展,惯例发展为零被视为假,非零值被视为真。但是,不必一定是这样。

Java:根本无法将数字视为布尔值

在Java中,truefalse是唯一的布尔值。数字不是布尔值,甚至不能转换为布尔值(Java语言规范,第4.2.2节):

整数类型和type之间没有强制转换boolean

该规则完全避免了这个问题-所有布尔表达式都必须在代码中显式编写。


1
Rebol和Red都对待0值的INTEGER!值是true,并有一个单独的NONE!除了LOGIC之外,将类型(只有一个值,NONE)视为条件假!假。在尝试编写将0视为false的JavaScript代码时,我感到非常沮丧。对于动态类型的语言来说,这是一个非常笨拙的决定。如果要测试可以为null或0的值,则必须编写if (thing === 0),这并不酷。
HostileFork

@HostileFork我不知道。我发现在动态语言中(和其他整数一样)0是有意义的true0在尝试使用NonePython时,有时会碰到一个,有时很难发现。
Morwenn 2014年

2
Ruby不是离群值。Ruby从Lisp那里得到了这一点(Ruby甚至被秘密地称为“ MatzLisp”)。Lisp是计算机科学中的主流语言。零也是POSIX shell中的真实值,因为它是一段文本: if [ 0 ] ; then echo this executes ; fi。错误数据值是一个空字符串,可测试错误性是命令的失败终止状态,由非零表示。
哈兹2015年

8

在处理一般情况之前,我们可以讨论您的反例。

字符串比较

实际上,对于多种比较而言,也是如此。这样的比较计算两个对象之间的距离。当对象相等时,距离最小。所以,当“比较成功”,该值为0。不过说真的,返回值strcmp不是一个布尔值,它是一个距离,而且有什么陷阱不知情的程序员做if (strcmp(...)) do_when_equal() else do_when_not_equal()

在C ++中,我们可以重新设计strcmp以返回一个Distance对象,该对象operator bool()将在0时重写以返回true(但随后您会被另一组问题所困扰)。或者在普通C语言中,只有一个streq函数,当字符串相等时返回1,否则返回0。

API调用/程序退出代码

在这里,您会担心出现问题的原因,因为这会导致错误决策。当事情成功时,您并不想特别了解任何事情-您的意图已经实现。因此,返回值必须传达此信息。它不是布尔值,而是错误代码。特殊错误值0表示“无错误”。其余范围代表您必须处理的本地有意义的错误(包括1,这通常意味着“未指定的错误”)。

一般情况

这给我们留下了一个问题:为什么是布尔值TrueFalse通常与分别为1和0,代表?

好吧,除了主观的“感觉更好”这样的说法外,还有一些我可以想到的原因(也有主观的):

  • 电路类比。电流接通1s,断开0s。我喜欢将(1,Yes,True,On)和(0,No,False,Off)一起使用,而不是混合使用

  • 内存初始化。当我memset(0)有一堆变量(它们是整数,浮点数,布尔值)时,我希望它们的值与最保守的假设相匹配。例如,我的总和最初是0,谓词是False,等等。

也许所有这些原因都与我的教育息息相关-如果从一开始就教我将0与True关联,那么我会走另一条路。


2
实际上,至少有一种编程语言将0视为true。Unix外壳。
Jan Hudec

+1解决真正的问题:Morwenn的大部分问题根本没有bool
dan04 2013年

@ dan04是的。整篇文章都是关于在许多编程语言中选择从int转换为的基本原理bool。比较和错误处理的东西仅仅是将其强制转换为不同于当前执行方式的示例。
Morwenn

6

从高级的角度来看,您正在谈论三种截然不同的数据类型:

  1. 一个布尔值。布尔代数中的数学约定是对使用0 false并将1对1使用true,因此遵循该约定是有意义的。我认为这种方式在直观上也更有意义。

  2. 比较的结果。这有三个值:<=>(请注意,他们都不是true)。对于它们来说,分别使用-1、0和1(或更常见的是负值,零和正值)是有意义的。

    如果您要检查是否相等,并且只有一个执行常规比较的函数,我认为您应该使用来使它明确strcmp(str1, str2) == 0。我发现!在这种情况下使用会造成混淆,因为它将非布尔值视为布尔值。

    另外,请记住,比较和平等不一定是同一回事。例如,如果您按某人的出生日期对其排序,Compare(me, myTwin)则应返回0,但Equals(me, myTwin)应返回false

  3. 功能的成功或失败,可能还包含有关该成功或失败的详细信息。如果您正在谈论Windows,则将调用此类型,HRESULT并且非零值不一定表示失败。实际上,负值表示失败和非负成功。成功值通常是S_OK = 0,但也可以是S_FALSE = 1或其他值。

造成混淆的原因是,实际上在C和其他一些语言中,三种逻辑上完全不同的数据类型实际上表示为单个数据类型(整数),并且您可以在条件中使用整数。但是我认为重新定义布尔值以在更简单的条件下使用某些非布尔类型没有意义。

另外,考虑在C中的条件中经常使用的另一种类型:指针。在那里,将NULL-pointer(表示为0)视为自然false。因此,遵循您的建议也将使指针的使用更加困难。(不过,就我个人而言,我更喜欢将指针与进行显式比较NULL,而不是将它们视为布尔值。)


4

零可能为假,因为大多数CPU都有一个可用于分支的零标志。它保存比较操作。

让我们看看为什么。

一些伪代码,因为观众可能不阅读汇编

c-源简单循环调用摆动10次

for (int foo =10; foo>0; foo-- ) /* down count loop is shorter */
{  
   wibble();
}

为此假装一些

0x1000 ld a 0x0a      'foo=10
0x1002 call 0x1234    'call wibble()
0x1005 dec a          'foo--
0x1006 jrnz -0x06      'jump back to 0x1000 if not zero
0x1008  

c-另一个简单的循环调用摆动10次

for (int foo =0; foo<10; foo-- ) /* up count loop is longer  */
{  
   wibble();
}

这种情况下的一些假装

0x1000 ld a 0x00      'foo=0
0x1002 call 0x1234    'call wibble()
0x1005 dec a          'foo--
0x1006 cmp 0x0a       'compare foo to 10 ( like a subtract but we throw the result away)
0x1008 jrns -0x08      'jump back to 0x1000 if compare was negative
0x100a  

一些更多的c源

int foo=10;
if ( foo ) wibble()

和组装

0x1000 ld a 0x10
0x1002 jz 0x3
0x1004 call 0x1234
0x1007  

看到那有多短?

一些更多的c源

int foo=10;
if ( foo==0 ) wibble()

和程序集(让我们假设有一个可以在不比较的情况下替换== 0的边际智能编译器)

0x1000 ld a 0x10
0x1002 jz 0x3
0x1004 call 0x1234
0x1007  

现在让我们尝试true = 1的约定

其他一些c源代码#define TRUE 1 int foo = TRUE; 如果(foo == TRUE)wibble()

和组装

0x1000 ld a 0x1
0x1002 cmp a 0x01
0x1004 jz 0x3
0x1006 call 0x1234
0x1009 

看到非零为真的情况有多短?

真正的早期CPU带有少量附加到累加器的标志。

检查a> b或a = b通常采用比较指令。

  • 除非B为零-在这种情况下,将零标志设置为一个简单的逻辑或或累加器中的所有位。
  • 或负数,如果使用二进制补码运算,则仅使用“符号位”即累加器的最高有效位。(大多数情况下我们这样做)

让我们重申一下。在某些较旧的CPU上,对于累加器等于0或小于零的累加器,不必使用比较指令。

现在您知道为什么零可能为假吗?

请注意,这是伪代码,没有真正的指令集看起来像这样。如果您知道汇编,就会知道我在这里简化了很多事情。如果您对编译器设计有所了解,则无需阅读此答案。任何对循环展开或分支预测一无所知的人,高级班都在203房间的大厅下。


2
您的观点在这里不是很清楚,因为一方面if (foo),它if (foo != 0)应该生成相同的代码,其次,您正在显示所使用的汇编语言实际上具有显式的布尔操作数并对其进行测试。例如jz手段jump if zero。换句话说if (a == 0) goto target;。而且数量甚至都没有直接测试。条件被转换为一个布尔标志,该标志存储在特殊的机器字中。实际上更像是cpu.flags.zero = (a == 0); if (cpu.flags.zero) goto target;
Kaz

没有Kaz,较旧的CPU不能那样工作。无需执行比较指令即可执行jz / jnz。这确实是我整个帖子的重点。
Tim Williscroft 2013年

2
我没有写任何关于比较指令的内容。
卡兹(Kaz)

您能举一个有jz指令但没有指令的处理器jnz吗?(或任何其他不对称的条件指令集)
Toby Speight

3

有许多答案表明,某些数学属性需要1和true之间的对应关系。我找不到任何此类属性,并建议它纯粹是历史惯例。

给定一个包含两个元素的字段,我们有两个操作:加法和乘法。我们可以通过两种方式在此字段上映射布尔运算:

传统上,我们将True标识为1,将False标识为0。将AND标识为*,将XOR标识为+。因此,OR饱和加法。

但是,我们可以轻松地将0标识为True,将1标识为False,然后将*标识为OR或将+标识为XNOR。因此AND饱和加法。


4
如果您遵循了Wikipedia上的链接,则可能会发现布尔代数的概念与两个元素的Galois字段的概念有关(en.wikipedia.org/wiki/GF%282%29)。符号0和1通常用于表示可加和可乘身份,分别的,因为实数也是一个字段,其标识是数字0和1
乔治

1
@NeilG我想乔治(Giorgio)试图说这不只是一个惯例。布尔代数中的0和1与GF(2)中的0和1基本相同,就加法和乘法而言,它们的实数几乎与0和1相同。
svick

1
@svick:否,因为您可以将乘法和饱和加法简单地重命名为OR和AND,然后翻转标签以使0为True,1为False。乔治说这是布尔逻辑的约定,后来被采纳为计算机科学的约定。
Neil G

1
@Neil G:否,您不能翻转+和*以及0和1,因为字段要求乘法而不是加法的分布性(请参阅en.wikipedia.org/wiki/Field_%28mathematics%29),但是如果您设置+:= AND和*:= XOR,则得到T XOR(T AND F)= T XOR F = T,而(T XOR T)AND(T XOR F)= F AND T =F。因此,通过翻转操作和标识,您可以没有一个领域了。因此,IMO将0和1定义为适当字段的标识似乎忠实地捕获了错误和真实。
Giorgio

1
@giorgio:我已经编辑了答案,以使事情变得显而易见。
尼尔·G

3

奇怪的是,零并不总是假的。

特别是,Unix和Posix约定将定义EXIT_SUCCESS为0(和EXIT_FAILURE1)。实际上,它甚至是标准的C约定

因此,对于Posix shell和exit(2)系统调用,0表示“成功”,从直觉上讲,它比false更真实。

特别是,shell if希望进程返回EXIT_SUCCESS(即0)以遵循其“ then”分支!

在Scheme中(但在Common Lisp或MELT中不是),0和nil(即()Scheme中)为true,因为唯一的错误值为#f

我同意,我在挑剔!


3

C用于靠近硬件的低级编程,有时您需要在该区域对同一数据在按位和逻辑操作之间切换。仅仅为了执行测试而需要将数值表达式转换为布尔值会使代码混乱。

您可以编写如下内容:

if (modemctrl & MCTRL_CD) {
   /* carrier detect is on */
}

而不是

if ((modemctrl & MCTRL_CD) != 0) {
    /* carrier detect is on */
}

在一个孤立的示例中,它还不错,但是必须这样做会令人讨厌。

同样,相反的操作。对于布尔运算的结果(如比较),仅产生0或1很有用。假设我们要根据modemctrl载波是否具有检测位来设置某个字的第三位:

flags |= ((modemctrl & MCTRL_CD) != 0) << 2;

在这里,我们必须使用!= 0,将双向&表达式的结果减少为01,但是由于结果只是一个整数,因此我们不必添加一些烦人的强制转换,以将布尔值进一步转换为整数。

即使现代C现在具有bool类型,它仍然保留这样的代码的有效性,这既是一件好事,又是因为否则会导致向后兼容性的巨大破坏。

C光滑的另一个例子:测试两个布尔条件作为四向切换:

switch (foo << 1 | bar) {  /* foo and bar booleans are 0 or 1 */
case 0: /* !foo && !bar */
   break;
case 1: /* !foo && bar */
   break;
case 2: /* foo && !bar */
   break;
case 3: /* foo && bar */
   break;
}

您不能不战胜C程序员!

最后,C有时充当一种高级汇编语言。在汇编语言中,我们也没有布尔类型。布尔值只是存储器位置或寄存器中的一位或零与非零值。整数零,布尔零和地址零都在汇编语言指令集中进行了相同的测试(甚至可能是浮点数零)。C和汇编语言之间的相似性很有用,例如,当C被用作编译另一种语言的目标语言时(甚至是强类型布尔值的语言!)。


0

布尔值或真值只有2个值。真假。

这些应该被表示为整数,但为比特(0和1)。

说出0或1之外的任何其他整数都不为假是令人困惑的陈述。真值表处理真值,而不是整数。

从预期的真值开始,-1或2将破坏所有真值表以及与它们相关的任何布尔逻辑。

  • 0 AND -1 ==?!
  • 0或2 ==?!

大多数语言通常都具有一种boolean类型,当将其转换为数字类型(例如整数)时会显示false,从而将其转换为整数值0。


1
0 AND -1 ==要将它们强制转换为布尔值。这就是我的问题,为什么要将它们强制转换为TRUEFALSE。我从没说过-也许我是这样做的,但那不是故意的-整数是对还是错,我问为什么将其转换为布尔值时,它们的确对哪个取值
Morwenn

-6

最终,您谈论的是破坏核心语言,因为某些API糟糕透顶。Crappy API并不是新手,您无法通过破坏语言来修复它们。这是一个数学事实,0为假,1为真,任何不遵守此规定的语言都会从根本上被破坏。三向比较是一种小众市场,它可以将结果隐式转换为零,bool因为它会返回三个可能的结果。旧的C API仅具有可怕的错误处理,而且也因C不具备没有可怕的接口所必需的语言功能而受到阻碍。

请注意,我并不是说对于不具有隐式integer-> boolean转换的语言。


11
“这是一个数学事实,0为假,1为真”。
R. Martinho Fernandes

11
您能否引用“ 0为假而1为真的数学事实”的参考?您的答案听起来很危险,就像在咆哮。
丹·皮切尔曼

14
这不是数学事实,但自19世纪以来一直是数学惯例。
查尔斯·格兰特

1
布尔代数由一个有限域表示,其中0和1是类似于加法和乘法运算的标识元素。这些运算分别是OR和AND。实际上,布尔代数的写法与普通代数非常相似,其中并置表示AND,+符号表示OR。因此例如abc + a'b'c手段(a and b and c) or (a and (not b) and (not c))
卡兹(Kaz)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.