【问题标题】:Why C++ allows arithmetic or enumeration values to be implicitly converted to boolean?为什么 C++ 允许将算术或枚举值隐式转换为布尔值?
【发布时间】:2010-11-04 05:28:57
【问题描述】:

C++ 标准在 4.12 节中说,

算术、枚举、指针或指向成员类型的指针的右值可以转换为 bool 类型的右值。零值、空指针值或空成员指针值转换为 false 任何其他值都转换为 true。

也就是说下面的代码是有效的,

if(5)
  std::cout << "WOW!";

它在语法上是有效的,但在语义上它没有任何意义。我的问题是为什么 C++ 允许这样奇怪的事情? AFAIK,它没有带来任何优势,而不是制造混乱。

【问题讨论】:

  • 这只是拖钓。不是一个真正的问题。
  • 海报有着不错的历史 - 是什么让您认为这不是真实的?
  • 它对世界各地使用 C(或汇编语言)长大的大量程序员来说具有语义意义。
  • 我不认为这是一个巨魔问题。我喜欢它——也经常想知道为什么会这样。

标签: c++ boolean


【解决方案1】:

认为这是历史性的,并且是 C 用来评估类似布尔概念的方式的副产品...

C 过去没有布尔类型,并且在 C 的“深入浅出”范式中,设置为 NULL 的指针和数字类型等也隐含为 false

如果您认为它是“无/零 == false”和“其他任何东西 == true”,它实际上是有道理的。

【讨论】:

  • C 使用 0 == false,而不是 0 == true 的原因是处理器实际上没有任何数据类型——只是不同大小的寄存器(如果你幸运的话)。硬件支持的“布尔”操作在寄存器中归结为 0 或不为零。 C 只是让程序员可以看到它。请记住,C 可以被认为是一种高级汇编语言,它非常有意义。
【解决方案2】:

实际上,在很多语言中,包括 C/Python/Perl/BASIC 非零整数/指针值 总是被认为是真的,0 被认为是假的。

这是许多编程语言中已知的约定,所以没有理由,为什么不应该在 C++ 中?

问题是为什么在 Java 中不是这样?

【讨论】:

  • 可能会强制程序员在逻辑条件中明确,让代码更具可读性。
【解决方案3】:

它来自C的产品。

另请注意,这些是(如果不是计算上的话,逻辑上)等价的:

如果 (x && y || z)

如果 (x * y + z)

(我知道这一点是因为 TI99/4a BASIC 没有 AND 或 OR 操作,所以 * 和 + 必须执行双重任务,而在 TI99/4a BASIC 中,布尔值的工作方式与 C 中一样。

【讨论】:

  • 不是这样。如果 x == 1 且 y == -1,则 x || y 为真,但 x + y 为假。
【解决方案4】:

我认为原因是历史。可能值得注意的是,下一个 C++ 版本(C++0x、C++1x)引入了不允许隐式转换为整数的作用域枚举,使得以下代码格式错误

enum class X { A, B, C };
if(X::B) { ... }

虽然数字允许隐式转换为布尔值对我来说很有意义,但对我来说枚举没有多大意义,因为主要目的是枚举值列表 - 仅次要实际值我相信,大多数情况下,一个枚举员都是感兴趣的。作用域枚举需要强制转换

if(static_cast<bool>(X::B)) { ... }

这增加了一些迄今为止所需的枚举的 C 兼容性所不允许的类型安全性(我想如果禁止普通枚举,这会破坏很多代码)。

【讨论】:

    【解决方案5】:

    这是特定硬件限制的产物。

    术语“int”、“short”、“bool”等。人。只要编译器在工作,就只有真正不同的语义含义——在运行时,它只是一个 1 字(8 位)值、2 字(16 位)值、4 字(32 位)值等。

    所以这里真正的问题不是“为什么 C++ 除了 5 作为布尔值”,而是“为什么是 C?”答案是,由于内存对齐,不可能在所有情况下都在任何地方存储单个位,因此编译器只使用了整个单词。在 C++ 中有一个指定的“bool”类型这一事实只是一些词汇上的挥手。

    【讨论】:

      【解决方案6】:

      这是推测,但我相信这是因为 C 被设计为一种极简语言。

      首先,布尔求值和算术求值非常相似,以至于它们实际上在 C 解析器中组合在一起,这减小了解析器的整体大小 - C++ 继承了这一点。

      其次,在汇编中测试非零结果通常使用单个操作码执行,该操作码测试寄存器的零值,如果为真,则跳转到语句的“else”部分。如果该值不为零,则执行自然会进入语句的“if-true”部分。

      【讨论】:

        【解决方案7】:

        从历史上看,C 相对于Weakly Typed language 而言,是为了简单和高效而不是健壮性而设计的。 Pascal 和类似语言的类型更强——枚举、指针、整数和布尔值不能在表达式中随机混合和匹配。

        C(和许多 C++)程序员都是在这种背景下长大的,你会经常看到像这样的惯用代码:

        while (1)
           dosomething(); // repeats forever
        

        .. 或...

        char * pointer;
        
        if (pointer)  // tests pointer for being != 0, which equals NULL.
          fred = *pointer;
        

        就个人而言,尽管使用 C/C++ 超过 20 年,我仍然觉得这第二个习语很难看,因为它在一行中做了两个“隐藏”转换/假设 - (NULL == 0) 和 (0 ==错误)。

        【讨论】:

          【解决方案8】:

          我找不到确切的引用,但人们总是说 C 结合了汇编语言的所有强大功能和灵活性以及汇编语言的安全性和易用性。

          通常处理器没有布尔、整数、ptr 类型。它们都只是内存或寄存器中的数字。

          我个人一直很喜欢这个成语:

          some_obj * thingy;
          if (thingy) ...
          

          这似乎是表达“事物存在”或“已初始化”的一种自然而简洁的方式。但是后来,我花了很多时间在汇编语言上。

          虽然我确实倾向于在 Objective-C、Java、C# 中使用“thingy == null”(或 nil),因为您只是感觉不太确定这些语言中发生了什么,离硬件更远。在某些语言中,甚至有人可以覆盖“==”运算符。

          你可以把“if (ptr)...”想象成调用一个隐式的“cast to boolean”操作符...

          【讨论】:

            【解决方案9】:

            那里有很好的答案,但我想再指出一件事:即使你不能说 boolean = numberboolean = pointer,使用 if(number)if(pointer) 构造仍然有意义。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2017-04-01
              • 1970-01-01
              • 2011-02-26
              相关资源
              最近更新 更多