【问题标题】:C language boolean expression return valueC语言布尔表达式返回值
【发布时间】:2014-03-18 19:47:02
【问题描述】:

C 语言没有布尔数据类型,而是使用整数。比较 == 和

【问题讨论】:

  • 通过使关系运算符返回01,语言允许“速记计算”:n += (n % 2 == 0); // increment n if it is even;此外,该语言已经采用任何非零值来表示真:只需在没有关系运算符的条件下直接使用它。
  • “返回任何非零值来表示真”——让它不明确会得到什么?它是否为实施者提供了更大的灵活性?他们如何利用这种灵活性?
  • C 在过去 15 年中一直使用布尔数据类型:_Bool / bool,在 stdbool.h 中定义。
  • C 确实有一个布尔类型。它称为_Bool(如果您有#include <stdbool.h>,则别名为bool)。它是由 1999 ISO C 标准添加的。但是比较运算符仍然产生int 结果。
  • 主要基于意见,尤其是查看 cmets 中各种帖子的讨论。

标签: c boolean-expression


【解决方案1】:

我相信这是一个武断的决定,要追溯到 C 的祖先语言 B。

引用Users' Reference to B

关系运算符<(小于)、<=(小于或等于)、>(大于)和>=(大于或等于)采用整数右值操作数。如果操作数彼此之间存在给定的关系,则结果为 1。否则结果为零。

没有解释这个特定的选择,也没有在ANSI C Rationale 或 Kernighan & Ritchie 的 1978 年第一版《C 编程语言》(K&R1) 中解释。

(B 的祖先语言 BCPL 有 truefalse 文字,其中 true 用所有位设置为 1 来表示。)

语言可能有不同的定义,但它仍然会在内部保持一致。例如,标准可以规定,如果条件为假,则关系运算符和相等运算符产生0 的结果,或者如果条件为真,则产生任意非零值。结果仍然可以在if 语句或任何其他需要条件的上下文中正确使用。很容易想象在 CPU 上,将真值表示为全比特而不是 1 会更有效——但语言标准不允许这样做。

几个标准库函数,例如isdigit(),可以返回任意非零值来指示一个真实的条件,这进一步表明这是一个任意选择。 (isdigit 自然是通过查表实现的,它可以产生除01 以外的值。

让相等和关系运算符产生01 会带来一些额外的便利。例如,这样可以轻松计算有多少条件为真:

int count = 0;
count += x == y;
count += foo > bar;
count += this <= that;

我的猜测是在第一个 B 编译器中使用 01 很方便,行为已记录在案,并且一直沿用至今。更改定义会破坏依赖于先前定义的代码。

即使在某些系统上效率相对较低,也不是什么大问题。等式或关系运算符的结果通常不会存储在任何地方,因此只要行为一致,编译器就可以随意表示结果。在某些情况下,它可能必须生成代码以将结果标准化为 01,但这可能并不重要。

【讨论】:

    【解决方案2】:

    如果条件表达式可以为真返回任何非零值,那么在将其存储到太小的变量(在极端情况下为一位位域)时可能会遇到麻烦。

    struct foo { unsigned int bar: 1; } baz;
    baz.bar = 1 == 1;
    

    如果 1 == 1 条件返回 2(或任何偶数),您将遇到麻烦,因为 baz.bar 最终会返回 0,在布尔上下文中评估为 false。

    【讨论】:

      【解决方案3】:

      当您在条件中使用关系运算符时,编译器会将其编译为“如果大于则跳转”或类似运算符,并且不会打扰实际计算 &lt;= 表达式的返回值。表达式总是返回 0 或 1 并不重要,因为该值从未被实际计算过。

      关系运算符返回 0 或 1 的唯一情况是它们的值用于更大的表达式中,例如算术或分配给变量。这比在分支中直接使用它们的情况要少得多,而且总是返回 1 的便利性也不是很高。

      【讨论】:

      • &lt; 不等于减法。假设x==INT_MAXy==INT_MIN
      • @KeithThompson:这是一个很好的观点。我把 SUB = CMP 的类比拿得太远了。
      【解决方案4】:

      在 C 语言中,0 为 false,无论是比较运算符或 if 语句的返回类型,还是您要检查的任何内容。然而,虽然 if() 语句将接受任何不为零的真值,但比较运算符 必须只返回一个 对象,因此决定该对象为“1”。这就是你是返回还是接受的区别。

      就像在任何其他函数中一样,例如int foo(int x){},您可以接受 x 的 任何 值,但您必须在离开函数之前实际选择要返回的内容。我想你可以返回一个随机数,但这有什么好处呢?而是选择了“1”。

      【讨论】:

      • 哦...为什么strcmp() 在字符串不同时返回any 负值或正值? :)
      • 我很确定它只是返回 str1 和 str2 之间的差异,但不是 100% 肯定的。
      • @KeithThompson 这不是被问到的问题。
      • @ciphermagi:C 标准仅规定 strcmp() 返回负值、0 或正值。它不一定是任何事物之间的区别——尽管这有时是一种方便的实现方式。
      • @ciphermagi:我相信这正是被问到的问题:“为什么不允许关系运算符返回任何非零值来表示真?”
      猜你喜欢
      • 2017-02-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多