如何习惯性地将布尔值转换为布尔值

How do I idiomatically convert a BOOL to a bool?

本文关键字:布尔值 转换 习惯性      更新时间:2023-10-16

<windows.h>标头带有自己的BOOL类型。偷看实现,似乎FALSE只是0的宏,而TRUE只是1的宏,但我不确定这是否指定。

BOOL转换为bool的惯用方法是什么?我可以想象很多可能的方法:

bool a = static_cast<bool>(x);
bool b = x ? true : false;
bool c = (x == TRUE);
bool d = (x != FALSE);
bool e = !!x;
// ...

不需要任何显式转换:

BOOL x = some_value;
bool b = x;

将数值类型隐式转换为bool,对于值为 0 false,对于任何非零值,true

顺便说一下,您已经告诉我们<windows.h>如何定义FALSETRUE。它如何定义BOOL?(从您的评论来看,这是typedef int BOOL;(

但某些编译器可能会警告这种隐式转换,即使它是完全有效的代码。编译器可以自由地警告他们喜欢的任何内容,包括你用来编写代码的丑陋字体。例如,G++不会抱怨转换,即使:

g++ -std=c++11 -pedantic -Wall -Wextra ...

但根据这个在线Visual C++编译器,VC++确实会产生一个警告:

warning C4800: 'BOOL' : forcing value to bool 'true' or 'false' (performance warning)

即使有static_cast,它仍然会产生警告。

您可以使用 !!xx ? true : false 来避免警告。但我不确定治愈是否比疾病更好。

执行此操作的简单而正确的方法是简单地分配值并依靠隐式转换来执行正确的操作(它会(。

如果您有避免编译器警告的其他要求,那么这将成为关于视觉C++而不是C++语言的问题。也可能有一些方法可以在不更改来源的情况下抑制某些警告 - 尽管这可能会在它们真正有意义时丢失相同的警告。在评论中,Dieter Lücking建议:

#pragma warning(disable: 4800) // forcing value to bool 'true' or 'false' (performance warning)

但这看起来仍然需要修改源。也许有类似的东西没有。

还有一件事:由于BOOL确实是 int 型,因此提出了以下解决方案:

bool c = (x == TRUE);

不等同于其他人。任何非零int都被视为 true,但只有值 1 等于 TRUE 。例如,上述将c设置为false如果x == 2 - 而if (x)仍然会将其视为真实条件。 切勿将相等的布尔值与 trueTRUE 进行比较。(将它们与falseFALSE进行比较更安全,但仍然没有必要;这就是!运算符的目的。

这一切都假设如果你有一个类型BOOL的值,你只关心它是伪造的还是真实的(零或非零(。不幸的是,情况可能并非总是如此。正如Ben Voight的回答所指出的那样,Microsoft的API至少包含一个函数GetMessage,该函数返回的BOOL结果不是简单的布尔值。在这种可怕的情况下,如果您需要区分多个非零值,则从 BOOL 转换为 bool 是不合适的。

最终,我责怪Microsoft为已经具有完美行为的内置bool类型的语言定义了类型BOOL实际上,这不太公平;它用于需要从 C 和 C++ 访问的 API。Microsoft对BOOL的定义可能可以追溯到他们的C实现,在那里它是有意义的 - 至少在C99之前,Microsoft仍然不支持。(不知道Microsoft的C编译器是否支持_Bool。即使有,_Bool也与int有一些语义差异,并且更改BOOL的定义可能会破坏一些代码 - 特别是使用GetMessage的代码。

很难说 win32 程序员会怎么做,但恕我直言,它应该通过以下方式完成:

bool c = (X == TRUE);

bool d = (x != FALSE);

我认为在宏(或任何其他预定义的东西
(上中继是一种不好的做法坚贞。

有一天,TRUE 可能会变成 0,FALSE 1 可能会变成 1 ;)

没有安全的方法可以执行此操作,因为 Win32 BOOL具有两个以上的值。

我使用宏:

#define _bool(b) (!!(b)) 

IMO,使我的代码更具可读性。

编辑:一位评论者质疑我在宏名称中使用下划线。为了解决这个问题,这里有一个新版本,它仍然是通用的,仍然使用相同的名称_bool,但根据这个是合规的。

namespace MyBool 
{
    template<typename T> inline bool _bool(const T b) 
    {
        return !!b;
    }
}
using namespace MyBool;

这在某种程度上是一个意见问题,但我认为对各种选择都有客观的论据。

最好的选择是:

bool d = (x != FALSE);

这使得意图对读者来说非常清楚,不依赖于隐式转换,并清楚地表明,除了简单的作业之外,还有更多的事情要做。

第二好的选择是:

bool b = x ? true : false;

但是,对于普通读者来说,这似乎是一种重言式。

我尽量避免在作业中进行隐式转换,因为获得错误的转换是令人惊讶的错误来源。 即使我知道隐式转换会做正确的事情,我也倾向于明确地做,这对将来阅读代码的人可能会有所帮助。 显式还可以让您保持启用转换警告,以便捕获您不知道自己正在(滥用(使用的其他隐式转换。

替代方案都有更严重的缺点。

bool a = static_cast<bool>(x);

这就像将方形钉子锤入圆孔中一样。 编写自然返回正确类型的表达式会更优雅。

bool c = (x == TRUE);

TRUE进行比较通常是一个坏主意,因为其他非零值会转换为 false,这几乎可以肯定是一个错误。

bool e = !!x;

与完全表达您意思的替代方案相比,太聪明了。 (我过去曾这样做过。

bool f = x;

MSVC++ 在纯隐式转换上发出的性能警告似乎是公平的。 编译器必须生成额外的代码才能将 int 转换为布尔值。 裸露的任务几乎没有提供关于这项额外工作的线索。 如果它处于一个紧密的循环中,你可能会关心。 (当然,static_cast选项的性能警告似乎令人震惊,但我们已经排除了它不那么优雅的可能性。

db的表达清楚地表达了意图,并清楚地表明这里发生的事情不仅仅是直接分配。