C++ 标准在第 4.12 节中说,
算术、枚举、指针或指向成员类型的指针的右值可以转换为 bool 类型的右值。零值、空指针值或空成员指针值转换为假,任何其他值都转换为真。
这意味着以下代码是有效的,
if(5)
std::cout << "WOW!";
它在语法上是有效的,但在语义上没有任何意义。我的问题是为什么 C++ 允许这样奇怪的事情?AFAIK,它没有带来任何优势,而不是制造混乱。
我认为这是历史性的,并且是 C 用来评估类似布尔概念的副产品...
C 过去没有布尔类型,并且在 C 的“底层”范式中,设置为 NULL 的指针和数字类型等也是隐式的false
。
如果您将其视为“无/零== false
”和“其他任何== true
”,它实际上是有道理的。
实际上,在许多语言中,包括 C/Python/Perl/BASIC 非零整数/指针值总是被认为是真,0 被认为是假。
这是许多编程语言中已知的约定,所以没有理由,为什么这不应该在 C++ 中?
问题是为什么在 Java 中不是这样?
它来自C的产品。
还要注意,这些是(如果不是计算上的话,逻辑上)等价的:
如果 (x && y || z)
如果 (x * y + z)
(我知道这一点是因为 TI99/4a BASIC 没有 AND 或 OR 操作,所以 * 和 + 必须执行双重任务,并且在 TI99/4a BASIC 中,布尔值在 C 中工作。
我认为原因是历史。可能值得注意的是,下一个 C++ 版本(C++0x、C++1x)引入了不允许隐式转换为整数的作用域枚举,使得以下代码格式错误
enum class X { A, B, C };
if(X::B) { ... }
不过,数字允许隐式转换为布尔值对我来说很有意义,但对我来说枚举没有多大意义,因为主要目的是枚举值列表 - 仅次要枚举器的实际值我相信大部分时间都很有趣。范围枚举将需要强制转换
if(static_cast<bool>(X::B)) { ... }
这增加了一些迄今为止所需的枚举的 C 兼容性所不允许的类型安全(我想如果禁止普通枚举,这会破坏很多代码)。
这是特定硬件限制的产物。
术语“int”、“short”、“bool”等。人。只要编译器正在工作,它就只有真正不同的语义含义——在运行时,它只是一个 1 字(8 位)值、2 字(16 位)值、4 字(32 位)值等。
所以这里真正的问题不是“为什么 C++ 除了 5 作为布尔值”,而是“为什么是 C?” 答案是,由于内存对齐,不可能在所有情况下都在任何地方存储一个位,所以编译器只使用了一个完整的单词。在 C++ 中有一个指定的“bool”类型的事实只是一些词汇上的挥手。
这是猜想,但我相信这是因为 C 被设计为一种极简语言。
首先,布尔求值和算术求值非常相似,以至于它们实际上在 C 解析器中组合在一起,这减小了解析器的整体大小 - C++ 继承了这一点。
其次,在汇编中测试非零结果通常使用单个操作码来测试寄存器的零值,如果为真,则跳转到语句的“else”部分。如果该值不为零,则执行自然会进入语句的“if-true”部分。
从历史上看,C 是一种相对弱类型的语言,其设计目的是为了简单和高效,而不是健壮性。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==FALSE )。
我找不到确切的引用,但人们总是说 C 结合了汇编语言的所有强大功能和灵活性以及汇编语言的安全性和易用性。
通常处理器没有布尔、整数、ptr 类型。它们都只是内存或寄存器中的数字。
就个人而言,我一直很喜欢这个成语:
some_obj * thingy;
if (thingy) ...
这似乎是表达“事物存在”或“已初始化”的一种自然而简洁的方式。但是后来,我花了很多时间在汇编语言上。
尽管我确实倾向于在 Objective-C、Java、C# 中使用“thingy == null”(或 nil),因为您只是感觉不太确定这些语言中发生了什么,离硬件更远。在某些语言中,甚至有人可以覆盖“==”运算符。
您可以将“if (ptr)...”视为调用隐式“强制转换为布尔”运算符...
那里有很好的答案,但我想再指出一件事:即使你不能说boolean = number
,拥有或构造boolean = pointer
仍然有意义。if(number)
if(pointer)