布尔值true - 正1还是负1?

13

我正在设计一种编程语言,正在尝试决定true应该是0x01还是0xFF。显然,所有非零值都将转换为true,但我正在努力确定精确的内部表示方式。

对于每个选择,有哪些优缺点?

11个回答

29

只要满足外部表示的规则,就无关紧要。

在这里我会借鉴C语言的做法,其中false被绝对定义为0,而true被定义为非false。这是一个重要的区别,与true的绝对值相比。除非你有一种仅有两个状态的类型,否则你必须考虑该值类型中的所有值,什么是true,什么是false。


这也使得语言实现更容易,可能也更有效率。true == !false。 - Henry B
1
当你遇到那些写下 if(condition==true) ... 的误导灵魂时,模糊的 true 定义会让你受到伤害。 - Mark Ransom
@Mark Ransom:这一点都不模糊。它是一切非零元素的集合。这是一个明确定义的集合。 - casperOne
“Fuzzy”不是恰当的词语,也许“宽松”更合适?如果“true”没有被定义为单一值,那么与“true”进行比较就会引起问题,而且有些人可能难以理解这一点。 - Mark Ransom
@Mark Ransom:这就是为什么如果true和false可以被表示的值集合超过两个,那么本质上进行与true比较是不好的。.NET通过显式创建布尔值类型并将其限制为仅有两个值来正确处理此问题。这里也需要做同样的事情。 - casperOne
显示剩余3条评论

23
0是假的,因为处理器有一个标志位,当寄存器被设置为零时,该标志位被设置。
其他任何值(0x01、0xff等)都不会设置其他标志位,但是当寄存器中有非零值时,零标志位被设置为假。
因此,在这里提倡将0定义为假,其他任何值定义为真是正确的。
如果你想要“定义”一个默认值为真,那么0x01比大多数值更好:
  • 它在每个位长度和符号位上都代表相同的数字
  • 如果零标志位不可用或使用成本高昂,只需要测试一个位就可以知道它是否为真
  • 在转换为其他类型时不需要担心符号扩展
  • 逻辑和算术表达式对其的操作相同

1
如果您想知道它是否为真,而零标志不可用或使用成本高昂,则只需要测试一个位。这似乎是错误的。如果0被定义为false,而1只是默认值,那么您无论如何都必须测试每个位吧? - Niki
也许“默认值”这个术语不太合适。在这种情况下,他建议将1作为TRUE的唯一值,但同时指出“!= 0”的价值。 - Will Hartung
Niki,我明白了 - 正如Will所指出的那样,我建议如果你选择强制执行“真实”值,那么你必须普遍地强制执行它。 - Adam Davis

14

在弱类型语言中,使用 -1 有一个优点——如果您搞错了并使用按位 and 运算符而不是逻辑 and 运算符,只要其中一个操作数已被转换为规范的布尔表示形式,您的条件仍将正确计算。 如果规范表示为 1,则情况并非如此。

  0xffffffff & 0x00000010 == 0x00000010 (true)
  0xffffffff && 0x00000010 == 0xffffffff (true)

但是

  0x00000001 & 0x00000010 == 0x00000000 (false)
  0x00000001 && 0x00000010 == 0xffffffff (true)

5
有人认为,在出现编程错误的情况下,它仍能以略微不那么可预测的方式继续工作,并不是一个卖点。 - tylerl
1
理解你的观点,但在弱类型语言中,你可能会得到错误的结果,而不知道它。你更喜欢偶然的正确性还是间歇性、无法检测的错误?这也是进行TDD的另一个原因吧。 - tvanfosson

11

为什么你选择非零值为真?在Ada中,真是TRUE,假是FALSE。没有从BOOLEAN进行隐式类型转换。


我同意。然而在我看来,Ada 有些过分了。 - fuzzy-waffle
2
内部上,它们最终必须成为1、0或其他值...我想不出任何处理器可以表示真/假而不至少使用二进制标志。 :-) - Brian Knoblauch
2
根据我的经验,隐式转换几乎总是导致代码难以理解和混乱。即使是显式转换也可能会引起问题。True 是 TRUE,false 是 FALSE。这些布尔值不是数字。 - Jim C
1
@Jim C - 问题在于,在某个层面上,它们必须成为我们共同架构上的数字... - Brian Knoblauch
3
是的,但是过于专注于这一点或泄露这种抽象概念可能是错误的选择,这取决于语言的目的。 - fuzzy-waffle
确实如此。这个话题需要被标记为“主观和有争议性” :-) - Brian Knoblauch

5

在我看来,如果你想坚持使用false=0x00,你应该使用0x01。0xFF通常表示:

  • 某些操作溢出的标志

或者

  • 一个错误标记

在这两种情况下,它很可能意味着false。因此,在*nix可执行文件的返回值约定中,true=0x00,任何非零值都是false。


+1 好的观点 - 看到一个参数为0xff的堆栈转储会引起警惕,但在这种情况下对程序员来说是一个误报。 - Not Sure
@Varkhan: 需要注意的是VB采用0xFF定义true,这绝对比它所值得的更麻烦。坦白地说,用绝对值而不是逻辑条件来定义true是一个可怕的想法。 - casperOne
@Varkhan:"true=0x00,任何非零值都为false" -- 这有些不准确:返回值为0表示“成功”,其他值则是“错误”代码。这是因为有许多类型的错误,但只有一种成功。/bin/true 返回0的事实是一个不幸的副作用。 - tylerl

4

-1比1更长,但最终并不重要,因为0是false,任何其他值都是true,并且你永远不会与true的确切表示进行比较。

请注意,对于那些给出负评的人,请说明原因。这个答案本质上与当前评分为+19的答案相同。所以这是21票的差异,而它们是基本相同的答案。

如果是因为-1的评论,那么是真的,实际定义“true”的人(例如:编译器编写者)将不得不使用-1而不是1,假设他们选择使用精确表示。 -1打字时间会比1长,最终结果将是相同的。这个声明很傻,它是为了好玩而发表的,因为两者之间没有真正的区别(1或-1)。

如果您要标记某些内容,请至少提供一个理由。


OP 正在询问内部表示法,而不是您如何键入值。例如,在 VB 中,真值存储为内存中的 -1。 - phuclv
@phuclv 是的,我的观点是这完全是主观的。没有所谓的“最佳”内部表示。 - TofuBeer

3

0xff是一个奇怪的选择,因为它有一个隐含的假设,即8位是您的最小存储单元。但是,想要比这更紧凑地存储布尔值并不那么罕见。

也许您可以通过考虑布尔运算符是否产生仅为1个0或1个位(这适用于任何符号扩展),或者全部为零或全部为1(并取决于带符号二进制补码量的符号扩展以在任何长度上保持全部1)来重新表述。

我认为使用0和1会使您的生活更简单。


3
优点和缺点都没有。只要您提供了从整数到布尔值的自动转换,它就是任意的,所以选择哪些数字并不重要。
另一方面,如果您不允许这种自动转换,那么您会有一个优点:您的语言中不会有完全任意的规则。您不会有`(7-4-3)==false`、`3*4+17=="Hello"`或者`"Hi mom!"==Complex(7,-2)`这样的情况。

2

我认为C方法是最好的选择。0表示假,其他任何值都表示真。如果你选择另一种映射来表示真,那么你就会面临一个问题,即存在不确定的值,既不是真也不是假。

如果你将要编译的语言针对特定指令集具有特殊支持,则应该让这个指导你。但是在没有任何额外信息的情况下,对于“标准”内部表示,我会选择-1(二进制中的所有1)。这个值可以很好地扩展到你想要的任何大小的布尔值(单个位、8位、16位等),如果你将“TRUE”或“FALSE”分解成较小的“TRUE”或“FALSE”,它仍然是相同的。(如果你将一个16位的TRUE=0x0001分解开,你将得到一个FALSE=0x00和一个TRUE=0x01)。


1
设计该语言,使得0为假,非零为真。无需进行任何“转换”,并且考虑“非零”而不是某个特定值将有助于您正确编写代码。
如果您拥有内置符号(例如“True”),那么可以选择一个值,但始终要考虑“非零即为真”而不是“0x01即为真”。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接