0
的计算结果是false
,而true
的任何其他[整数]值却是大多数编程语言?字符串比较
因为这个问题似乎有点太简单了,我将对自己进行一些解释:首先,对于任何程序员而言,这似乎都是显而易见的,但是为什么没有一种编程语言-实际上可能存在,但我没有使用过-在哪里
0
求和为true
,所有其他[整数]取值为false
?这句话似乎是随机的,但我举了一些例子,可能是个好主意。首先,让我们以字符串三向比较为例,以C的strcmp
为例:任何以C为第一语言的程序员都可能会编写以下代码: if (strcmp(str1, str2)) { // Do something... }
由于
strcmp
返回0
,当字符串相等时,其求值为false
,这是开始的程序员尝试去做的尝试失败了,他一开始通常不理解为什么。如果将0
评估为true
,则可以在比较相等性时以最简单的表达式(上面的表达式)使用此函数,并且仅在需要时才对-1
和1
进行适当的检查。在大多数情况下,我们通常会将返回类型视为bool
。在我们看来,我们引入一种新类型sign
,它仅使用值-1
,0
和1
。那可能很方便。想象一下,在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);
pre >
该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
在false
的条件下求值为if
,而所有no
的情况都求值为true
。在许多情况下,“有效”代表一种情况,而“无效”代表许多可能的原因。如果我们这样考虑,将0
评估为true
,将其余部分评估为false
会更有意义。
结论
我的结论本质上是我最初的问题:考虑到我上面的几个示例以及也许我没有想到的更多示例,为什么我们设计0
为false
而其他值为true
的语言?
以下-up:很高兴看到有很多答案,其中有很多想法,并且有很多可能的原因。我喜欢您似乎对此充满热情。我本来是出于无聊的问题而提出这个问题的,但由于您似乎太热情了,所以我决定进一步探讨一下Math.SE上布尔选择0和1的逻辑依据:)
#1 楼
0
之所以是false
,是因为它们在公共半环中都是零元素。尽管它们是不同的数据类型,但由于它们属于同构代数结构,因此在它们之间进行转换在直觉上也是有意义的。
0
是加法的标识,并且是零的标识。这适用于整数和有理数,但不适用于IEEE-754浮点数:0.0 * NaN = NaN
和0.0 * Infinity = NaN
。
false
是布尔异或(the)的标识,而布尔和(∧)的标识为零。如果布尔值表示为{0,1}(以2为模的整数集),则可以将⊻视为没有进位的加法,将∧视为乘法。他们认为零。重复是一个,但是重复和串联不会分布,因此这些操作不会形成半环。
此类隐式转换在小型程序中很有用,但在大型程序中,它们会使程序更难以推理关于。语言设计中众多折衷方案之一。评论
很高兴您提到列表。 (顺便说一句,nil既是空列表[]也是Common Lisp中的false值;是否存在合并来自不同数据类型的身份的趋势?)您仍然必须解释为什么将false视为加法身份和true是自然的作为乘法身份,而不是相反。不可能将true视为AND的标识,并将OR视为零吗?
–乔治
13年5月16日在7:58
+1表示相似的身份。最后,答案不仅仅归结为“常规,应对”。
–l0b0
13年5月16日在9:20
+1用于提供具体且非常古老的数学的详细信息,在该数学中已经遵循并且很长一段时间才有意义
–吉米·霍法(Jimmy Hoffa)
13年5月16日在15:22
这个答案没有道理。半环(布尔值和/或)的标识和零也为true。 appart约定,没有理由认为false比true更接近0。
–TonioElGringo
15年11月17日在16:08
@TonioElGringo:true和false之间的区别是XOR和XNOR之间的区别。一个人可以使用AND / XOR来形成同构环,其中true是乘法恒等式,false是加法恒等式,或与OR和XNOR,其中false是乘法恒等式,true是加法恒等式,但是XNOR通常不被视为通用XOR的基本操作方式。
–超级猫
17年5月9日17:10#2 楼
因为数学有效。
FALSE OR TRUE is TRUE, because 0 | 1 is 1. ... insert many other examples here.
传统上,C程序具有类似
if (someFunctionReturningANumber())
而不是
if (someFunctionReturningANumber() != 0)
,因为零被误认为是错误的概念。评论
语言的设计是这样的,因为数学很有意义。首先。
–罗伯特·哈维(Robert Harvey)
13年5月15日在19:57
@Morwenn,它可以追溯到19世纪和George Boole。人们将False表示为0,将True表示为!0的时间比计算机早。
–Charles E. Grant
13年5月15日在20:03
我不明白为什么仅更改所有定义以使AND为+而OR为*,则数学无法以其他方式起作用。
–尼尔G
13年5月15日在21:49
确实:数学是双向的,这个问题的答案似乎是纯粹的传统。
–尼尔G
13年5月15日在21:51
@Robert如果您能在帖子中阐明“数学基础”,那就太好了。
–phant0m
13年5月15日在21:59#3 楼
正如其他人所说,数学是第一位的。这就是为什么0是false
和1是true
的原因。
我们在说什么数学?布尔代数可追溯到1800年代中期,远早于数字计算机的出现。
您还可以说该约定源自命题逻辑,甚至比布尔代数还早。这是程序员知道和喜欢的许多逻辑结果的形式化(false || x
等于x
,true && x
等于x
等)。 。考虑以二进制计数。布尔代数是此概念的起源及其理论基础。像C这样的语言约定只是一个简单的应用程序。评论
当然可以。但是将其保持为“标准”方式与通用算术非常吻合(0 + 1 = 1,而不是0 + 1 = 0)。
– joshin4colours
13年5月15日在21:46
是的,但是如果您也颠倒了定义,则可能会用+和OR或*编写AND。
–尼尔G
13年5月15日在21:47
数学不是第一位的。数学认识到0和1构成一个字段,其中AND就像乘法,而OR就像加法。
–卡兹
13年5月16日在0:57
@Kaz:但是带有OR和AND的{0,1}不会形成字段。
–乔治
13年5月16日在11:20
令我有些烦恼的是,更多答案和评论都说true =1。这不太准确,因为true!= 0并不完全相同。为什么要避免类似if(something == true){...}这样的比较的一个原因(不是唯一的原因)。
– JensG
13年11月12日在20:07
#4 楼
我认为这与电子产品的“继承性”以及布尔代数有关,其中
br />
0
=off
,negative
,no
,false
strcmp在实现字符串相等时返回0,因为它的实际作用是计算两个字符串之间的“距离”。恰好被认为是假的0也只是一个巧合。
成功返回0是有意义的,因为在这种情况下,0表示没有错误,而其他任何数字都将是错误代码。使用任何其他数字来获得成功意义不大,因为您只有一个成功代码,而您可能有多个错误代码。您使用“它起作用了吗?”如if语句表达式,并说0 = yes更有意义,但该表达式更正确:“是否出错?”然后您会看到0 = no很有意义。对1
的思考在这里并没有什么意义,因为实际上是on
。评论
哈哈,您是第一个明确声明返回错误问题的人。我已经知道我以自己的方式解释它,也可以通过其他方式解释它,但是您是第一个明确表达它的人(在许多答案和评论中)。实际上,我不会说一种或另一种方式没有任何意义,但更多的是两种方式都具有不同的意义:)
–莫文
13年5月16日在11:11
实际上,我想说0代表成功/没有错误是当其他整数代表错误代码时唯一有意义的事情。在其他情况下,0也恰好代表假并不重要,因为在这里我们根本不是在谈论真或假;)
–Svish
13年5月16日在12:09
我有相同的想法,所以我提高了
–user60812
13年5月17日在12:49
关于strcmp()计算距离的观点非常好。如果它被称为strdiff(),那么if(!strdiff())将非常合乎逻辑。
–凯文·考克斯(Kevin Cox)
2014年7月10日在21:53
“电子学,其中0 =假,1 =真”-即使在电子学中,这也只是一个惯例,并不是唯一的惯例。我们称其为正逻辑,但也可以使用负逻辑,其中正电压表示假,负电压表示真。然后,您用于AND的电路变为OR,或OR变为AND,依此类推。根据De Morgan的法律,所有这些最终都是等效的。有时,为了方便起见,您会发现以负逻辑实现的电子电路的一部分,此时该部分中信号的名称会在信号上方标有一个条形。
–法律
18年7月21日在1:34#5 楼
如本文所述,值false
和true
不应与整数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(+)和逻辑al AND(*)。
注意。如果翻转运算(XOR是乘法,而AND是加法),则乘法不会在加法上分配,并且您将不再有字段。在这种情况下,您没有理由调用两个元素0和1(以任何顺序)。
还请注意,您不能选择操作OR而不是XOR:无论您如何将OR / AND解释为加法/乘法,结果结构不是字段(并非所有的逆元素都按字段公理的要求存在)。
关于C函数:
许多函数返回一个为错误代码的整数。 0表示没有错误。
直观地,函数strcmp
计算两个字符串之间的差。 0表示两个字符串之间没有区别,即两个字符串相等。
上面的直观解释可以帮助您记住对返回值的解释,但仅查看库文档甚至更加容易。评论
+1表示如果您任意交换这些,数学将不再有效。
–吉米·霍法(Jimmy Hoffa)
13年5月16日在15:25
翻转:给定一个包含两个元素以及运算符*和+的字段,我们将True标识为0,将False标识为1。将OR标识为*,将XOR标识为+。
–尼尔G
13年5月17日下午5:48
您会发现这两个标识都是在同一字段上完成的,并且都与布尔逻辑规则一致。很遗憾,您的备注不正确:)
–尼尔G
13年5月17日在5:49
如果假设True = 0,且XOR为+,则True必须是XOR的标识。但这不是因为True XOR True = False。除非您在True上重新定义XOR操作,以便True XOR True = True。然后,您的构造当然会工作,因为您刚刚对事物进行了重命名(在任何数学结构中,您始终可以成功进行名称排列并获得同构结构)。另一方面,如果让True,False和XOR具有其通常的含义,则True XOR True = False和True不能为加法标识,即True不能为0。
–乔治
13年5月17日在7:30
@Giorgio:我根据您在最近的评论中的评论更正了我的构造……
–尼尔G
13年5月17日在7:30
#6 楼
您应该考虑使用替代系统也是可以接受的设计决策。
Shells:0退出状态为true,非零为false
shell处理0退出的示例状态已经为真。
$ ( 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"
理由是只有false
和nil
应该是假的。对于许多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中,true
和false
是唯一的布尔值。数字不是布尔值,甚至不能转换为布尔值(Java语言规范,第4.2.2节):
整数类型和类型boolean
之间没有强制转换。 >
该规则完全避免了这个问题-所有布尔表达式都必须在代码中明确编写。评论
Rebol和Red都对待0值的INTEGER!值是true,并有一个单独的NONE!除了LOGIC之外,将类型(只有一个值,NONE)视为条件假!假。在尝试编写将0视为false的JavaScript代码时,我感到非常沮丧。对于动态类型的语言来说,这是一个非常笨拙的决定。如果要测试可以为null或0的值,则必须编写if(thing === 0),那真是太酷了。
– HostileFork说不信任SE
2014年4月10日20:52
@HostileFork我不知道。我发现在动态语言中0为true(与其他整数一样)是有意义的。当我尝试在Python中捕获None时,有时会碰到一个0,这有时很难发现。
–莫文
2014年4月10日在21:22
Ruby不是离群值。 Ruby从Lisp那里得到了这一点(Ruby甚至被秘密地称为“ MatzLisp”)。 Lisp是计算机科学中的主流语言。零也是POSIX shell中的真实值,因为它是一段文本:if [0];然后回声执行; fi。错误数据值是一个空字符串,可测试错误是命令的失败终止状态,由非零表示。
–卡兹
15年1月22日在19:42
#7 楼
在解决一般情况之前,我们可以讨论您的反例。
字符串比较
实际上,许多比较都一样。这样的比较计算两个对象之间的距离。当对象相等时,距离最小。因此,当“比较成功”时,该值为0。但是,实际上,strcmp
的返回值不是布尔值,而是一个距离,这是陷阱,这些陷阱使无意识的程序员在做if (strcmp(...)) do_when_equal() else do_when_not_equal()
。
在C ++中我们可以重新设计strcmp
以返回一个Distance
对象,该对象将覆盖operator bool()
以在0时返回true(但是您可能会被另一组问题咬住)。字符串相等,否则为0。
API调用/程序退出代码
在这里,您要担心出现问题的原因,因为这会导致错误的决策。当事情成功时,您并不想特别了解任何事情-您的意图已经实现。因此,返回值必须传达此信息。它不是布尔值,而是错误代码。特殊错误值0表示“无错误”。范围的其余部分代表您必须处理的本地有意义的错误(包括1,这通常意味着“未指定的错误”)。
一般情况
问题:为什么布尔值streq
和True
分别通常用1和0表示?我可以想到:电路类比。电流接通1s,断开0s。我喜欢将(1,Yes,True,On)和(0,No,False,Off)一起使用,而不是使用其他混合内存初始化。当我False
一堆变量(它们是整数,浮点数,布尔值)时,我希望它们的值与最保守的假设相匹配。例如。我的总和最初是0,谓词是False,等等。
也许所有这些原因都与我的教育息息相关-如果从一开始就被教导我将0与True关联,那么我会走另一条路。评论
实际上,至少有一种编程语言将0视为true。 Unix外壳。
– Jan Hudec
13年5月16日在10:55
+1解决真正的问题:Morwenn的大部分问题根本不是关于布尔。
– dan04
13年5月17日在14:02
@ dan04是的。整篇文章都是关于在许多编程语言中从int转换为bool的基本原理。比较和错误处理的东西仅仅是将其强制转换为不同于当前执行方式的示例。
–莫文
13年5月21日在6:40#8 楼
从高级的角度讲,您正在谈论三种完全不同的数据类型:
布尔值。布尔代数的数学约定是对false
使用0,对true
使用1,因此遵循该约定是有意义的。我认为这种方式在直观上也更有意义。
比较的结果。它具有三个值:<
,=
和>
(请注意,它们都不是true
)。对于它们,有意义的是分别使用-1、0和1的值(或更常见的是使用负值,零和正值)。
如果要检查相等性而且您只有一个执行一般比较的功能,我认为您应该使用strcmp(str1, str2) == 0
之类的方式使其明确。我发现在这种情况下使用!
令人困惑,因为它将非布尔值视为布尔值。
此外,请记住,比较和相等不必相同。例如,如果按人的出生日期对其进行排序,则Compare(me, myTwin)
应返回0
,而Equals(me, myTwin)
应返回false
。
函数的成功或失败,可能还包含有关该成功或失败的详细信息。如果您正在谈论Windows,则此类型称为HRESULT
,并且非零值不一定表示失败。实际上,负值表示失败和非负成功。成功值通常是S_OK = 0
,但也可以是S_FALSE = 1
或其他值。
混淆来自以下事实:三个逻辑上完全不同的数据类型实际上表示为单个数据类型(整数)使用C语言和其他一些语言,并且您可以在条件中使用整数。但是我认为重新定义布尔值以在更简单的条件下使用某些非布尔类型没有道理。
另外,考虑在C中的条件中经常使用的另一种类型:指针。在那里,将NULL
指针(表示为0
)视为false
是很自然的。因此,遵循您的建议也将使指针的使用更加困难。 (尽管就我个人而言,我更喜欢将指针与NULL
进行显式比较,而不是将它们视为布尔值。)#9 楼
零可能是错误的,因为大多数CPU都有一个可用于分支的ZERO标志。
它节省了比较操作。
让我们看看为什么。 ,因为观众可能不阅读汇编
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 wi的智能编译器)没有比较)
0x1000 ld a 0x10 0x1002 jz 0x3 0x1004 call 0x1234 0x1007
现在让我们尝试使用true = 1的约定
更多的c源代码
#define TRUE 1
int foo = TRUE;
if(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房间的大厅下。评论
您的观点在这里不是很清楚,因为一件事if(foo)和if(foo!= 0)应该生成相同的代码,其次,您正在显示正在使用的汇编语言实际上具有显式的布尔操作数并为他们测试。例如,jz表示如果为零则跳转。换句话说,如果(a == 0)转到目标;。而且数量甚至都没有直接测试。条件被转换为一个布尔标志,该标志存储在特殊的机器字中。实际上更像是cpu.flags.zero =(a == 0);如果(cpu.flags.zero)转到目标;
–卡兹
13年5月16日在17:02
没有Kaz,较旧的CPU不能那样工作。无需执行比较指令即可执行jz / jnz。这真的是我整个帖子的重点。
–蒂姆·威利斯克罗夫特(Tim Williscroft)
13年5月19日在2:04
我没有写任何关于比较指令的内容。
–卡兹
13年5月19日下午2:35
您能引用一个带有jz指令但没有jnz的处理器吗? (或任何其他非对称的条件指令集)
– Toby Speight
16年11月9日在16:58#10 楼
有许多答案表明1和true之间的对应关系是某些数学属性所必需的。我找不到任何这样的属性,并建议它纯粹是历史惯例。
给出一个包含两个元素的字段,我们有两个操作:加法和乘法。我们可以通过两种方式在该字段上映射布尔运算:
传统上,我们将True标识为1,将False标识为0。将AND与*标识,将XOR与+标识。因此,OR是饱和的。
但是,我们可以轻松地将0标识为True,将1标识为False,然后将*标识为OR,将+标识为XNOR。因此AND饱和加法。评论
如果您遵循了Wikipedia上的链接,则可能会发现布尔代数的概念与两个元素的Galois字段的概念有关(en.wikipedia.org/wiki/GF%282%29)。传统上,符号0和1分别用于表示加法和乘法身份,因为实数也是一个其身份为数字0和1的字段。
–乔治
13年5月15日在22:08
@NeilG我认为Giorgio试图说这不只是一个惯例。布尔代数中的0和1与GF(2)中的0和1基本相同,就加法和乘法而言,它们的实数几乎与0和1相同。
– svick
13年5月15日23:47
@svick:否,因为您可以将乘法和饱和加法简单地重命名为OR和AND,然后翻转标签,以便0为True,1为False。乔治说这是布尔逻辑的约定,后来被采用为计算机科学的约定。
–尼尔G
13年5月16日在0:49
@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定义为适当字段的标识似乎忠实地捕获了错误和真实。
–乔治
13年5月16日在1:08
@giorgio:我已经编辑了答案,以使事情变得显而易见。
–尼尔G
13年5月17日下午5:55#11 楼
奇怪的是,零并不总是假。
特别是,Unix和Posix约定是将EXIT_SUCCESS
定义为0(而EXIT_FAILURE
定义为1)。实际上,它甚至是标准的C约定!
因此,对于Posix shell和exit(2)系统调用,0表示“成功”,从直觉上讲,它比false更真实。特别是,shell的if
希望进程返回EXIT_SUCCESS
(即0)跟随其“ then”分支! Scheme)为true,因为唯一的错误值为()
我同意,我很挑剔!#12 楼
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
,才能将双向&
表达式的结果减少为0
或1
,但是因为结果只是一个整数,所以我们不必添加一些烦人的强制转换来将布尔值进一步转换为整数。
即使现代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; }
e C程序员,无需战斗!
最后,C有时充当一种高级汇编语言。在汇编语言中,我们也没有布尔类型。布尔值只是存储器位置或寄存器中的一位或零与非零值。整数零,布尔零和地址零都在汇编语言指令集中进行了相同的测试(甚至可能是浮点数零)。 C和汇编语言之间的相似性很有用,例如,当C被用作编译另一种语言的目标语言时(甚至是具有强类型布尔值的语言!)#13 楼
布尔值或真值只有2个值。是非题。
这些不应该表示为整数,而应该表示为位(0和1)。
说0或1之外的任何其他整数都不是false令人困惑的声明。真值表处理的是真值,而不是整数。
从预期的真值中,-1或2会破坏所有真值表以及与之相关的布尔逻辑。
0 AND -1 ==?!
0 OR 2 ==?!
大多数语言通常具有boolean
类型,当将其转换为数字类型(例如整数)时,会显示false强制转换为0的整数。评论
0 AND -1 ==要将它们强制转换为布尔值。这就是我的问题,为什么将它们强制转换为TRUE或FALSE。我从没说过-也许我是这样做的,但那不是故意的-整数是对还是错,我问为什么将其转换为布尔值时,它们的值会取整数。
–莫文
13年5月15日在21:25#14 楼
最终,您谈论的是破坏核心语言,因为某些API糟糕透顶。 Crappy API并不是新手,您无法通过破坏语言来修复它们。这是一个数学事实,0为假,1为真,任何不遵守此规定的语言都会从根本上被破坏。三向比较是一种利基分析,它可以将结果隐式转换为bool
,因为它会返回三个可能的结果,因此没有关系。旧的C API仅具有可怕的错误处理,并且也因C没有不具备不可怕接口的必要语言功能而受阻。
请注意,我并不是说那些没有隐式整数->布尔值转换。评论
“这是一个数学事实,0为假,1为真”。
– R. Martinho Fernandes
13年5月15日在19:55
您能否引用“ 0为假而1为真的数学事实”的参考?您的答案听起来很危险,就像在咆哮。
–丹·皮切尔曼(Dan Pichelman)
13年5月15日在19:57
这不是数学事实,但自19世纪以来一直是数学惯例。
–Charles E. Grant
13年5月15日在20:06
布尔代数由一个有限域表示,其中0和1是类似于加法和乘法运算的标识元素。这些运算分别是OR和AND。实际上,布尔代数的写法与普通代数非常相似,其中并置表示AND,而+符号表示OR。因此,例如abc + a'b'c表示(a and b和c)或(a and(not b)和(not c))。
–卡兹
13年5月16日在1:04
评论
strcmp()不是true或false的好例子,因为它返回3个不同的值。当您开始使用shell时,您会感到惊讶,其中0表示true,其他表示false。@ ott--:在Unix shell中,0表示成功,非零表示失败-与“ true”和“ false”不太一样。
@KeithThompson:在Bash(和其他shell)中,“成功”和“失败”实际上与“ true”和“ false”相同。例如,考虑以下语句是否为true;然后 ... ; fi,其中true是返回零的命令,它告诉是否运行....
硬件中没有布尔值,只有二进制数,并且在大多数历史ISA中,在所有条件分支指令中,非零数都被视为“ true”(除非它们使用标志代替)。因此,低级语言必须完全遵循底层的硬件属性。
@MasonWheeler具有布尔类型并不表示任何内容。例如python确实具有布尔类型,但是比较/如果条件等可以具有任何返回值。