【问题标题】:Why is there a performance warning on cast pointer to bool?为什么对 bool 的强制转换指针有性能警告?
【发布时间】:2010-12-23 07:14:54
【问题描述】:

Extends.

当我做类似的事情时,我觉得我很酷:

布尔 hasParent() { 返回 this->parentNode ; }

即使使用 (bool) 强制转换,警告仍然不会消失。

其中 this->parentNode 在没有父节点时为 NULL。

但我得到了:

警告 C4800:“节点 *”:强制值为布尔值“真”或“假”(性能警告)

怎么了,哟?为什么这是性能警告?我认为不写这样的东西会更有效率:

布尔 hasParent() { 如果(这个->父节点) 返回真; 别的 返回假; }

但是第二个版本没有产生任何警告,编译器似乎更开心了。哪个更快?

【问题讨论】:

  • 解决方法:将(expr) 更改为!!(expr)
  • 看起来太刺激了

标签: c++ casting performance


【解决方案1】:

编译器需要生成额外的代码来将指针转换为布尔值。它基本上是与零的比较,如果不为零,则将结果设置为一。

00000000004005e0 <_Z4testPv>:
bool test(void* adr) {
  4005e0:       48 85 ff                test   %rdi,%rdi
  4005e3:       0f 95 c0                setne  %al
    return adr;
}
  4005f8:       c3                      retq

这不是从源代码直接可见的,因此编译器认为这是应该警告用户的事情。

【讨论】:

  • 这不是因为它将指针转换为布尔值,而是因为它返回了一个布尔值。如果您比较两个布尔值,则会生成相同的代码,但它会根据优化设置使用不同的寄存器。
【解决方案2】:

Microsoft Connect 上有关于此的讨论 (What is the performance implication of converting to bool in C++?)。给微软的例子是:

$ cat -n t.cpp && cl -c -W3 -O2 -nologo -Fa t.cpp
1 bool f1 (int i)
2 {
3 return i & 2;
4 }
5
6 bool f2 (int i)
7 {
8 const bool b = i & 2;
9 return b;
10 }
11
12 bool f3 (int i)
13 {
14 const bool b = 0 != (i & 2);
15 return b;
16 }
t.cpp
t.cpp(3) : warning C4800: 'int' : forcing value to bool 'true' or 'false' (performance warning)
t.cpp(8) : warning C4800: 'int' : forcing value to bool 'true' or 'false' (performance warning)

微软的回应(来自负责警告的开发人员)是:

这个警告非常有用,昨天在我的代码中发现了一个错误。我认为 Martin 在断章取意地使用“性能警告”。

这与生成的代码无关,而与程序员是否已发出将值从 int 更改为 bool 的意图有关。这样做是有代价的,用户可以选择一致地使用“int”而不是“bool”(或者反之亦然)以避免“boolifying”代码生成。在下面的第三种情况下,警告被抑制,因为他清楚地表明他打算接受 int->bool 转换。

这是一个古老的警告,可能已经过时了,但它的行为与此处设计的一样

所以基本上,MS 开发人员似乎在说,如果你想将int“转换”为bool,你应该更恰当地使用“return this-&gt;parentNode != 0”而不是隐式或显式转换。

就我个人而言,我很想了解更多有关警告发现的错误类型的信息。我认为这个警告不会有很大的价值。

【讨论】:

  • 我也认为这个警告是没用的,但我又对 MS VC 有偏见 ;-)
  • 我认为应该有一个编译器标志来启用那些无用的警告。这个和“大多数 C 和一些 C++ 标准库已被弃用”警告总是让我产生一种冲动,在使用 VC 时完全禁用警告。
  • 另外,return this-&gt;parentNode != 0 更容易出错,因为return this-&gt;parentNode = 0 可能存在拼写错误。
  • bobobobo:任何理智的编译器(至少 gcc)都会对此发出警告。如果你正确使用“const”,hasParent() 将是一个 const 函数,所以它会是一个编译错误。
  • 如果警告是为了捕捉错误,那么它是错误的。
【解决方案3】:

为什么这是一个性能警告?

编译器正在转这个:

bool hasParent()
{
  return this->parentNode;
}

进入:

bool hasParent()
{
  return this->parentNode != 0;
}

这比您查看代码所花费的时间要多一个时钟周期。这是一个微不足道的性能差异。

我认为最好还是明确地写出!= 0,因为它可以使代码更清晰并且可以消除警告。

【讨论】:

  • 哦,天哪。 3,000,000,000 个时钟周期中的 1 个?太多了。
  • 在某些用途中,甚至 1 个时钟周期也很重要。
  • 两者实际上并没有什么不同。仅当parentNode 是一个布尔值时,循环计数差异才适用。由于它是一个地址,它将是本机字长,您不能只比较低 8 位并称其为好。如果它不是地址并且是布尔值,请确保您可以使用不同的指令来比较较小的操作数,并且它可能会更快一些(几个周期或更好的流水线)。
【解决方案4】:

这样写会更有效率:

bool hasParent()
{
    return  this->parentNode != NULL;
}

【讨论】:

  • 错了,编译器会生成和原来一样的代码。
  • user9876,谁说它会生成更高效的代码?它可以节省打字。
  • 写入部分是epsilon效率更高。执行部分是 epsilon squared 更有效。将此称为性能警告只是关于性能的一般愚蠢愚蠢的一部分。
  • 我的意思是与 if {} else {} 块相比。这也消除了警告。
  • @Martin:我知道你做到了。我只是对最初的编译器警告感到愤怒。对不起。
【解决方案5】:

转换为bool 不会使警告消失is by design 的事实:

将表达式转换为 bool 类型不会禁用警告,这是设计使然。

我会推荐 MSDN 描述的警告 C4800 推荐的方法:

return this->parentNode != NULL;

这清楚地表明,如果 parentNode 不是空指针,则返回 true;如果 parentNode 是空指针,则返回 false

【讨论】:

  • 好答案!从MS的角度来看。我想表示我不同意.. 在我的 if 语句等中,我从不检查 if( object == NULL ),因为输入 if( object = NULL ) 并以这种方式创建错误的可能性。正是出于这个原因,我检查了if( object )if( !object )#pragma warning (disable:4800),我现在写。
  • 我更喜欢!!value。它更短更通用。
  • +1 使转换显式使您的意图对阅读代码的下一个程序员来说显而易见,并承认隐式转换的性能成本。
  • 不回答问题:“为什么会有性能警告...”?
  • 一些编码标准建议将运算符参数切换到 NULL == 对象,因此拼写错误 NULL = 对象会导致编译器错误。
【解决方案6】:

实际上我认为他们会优化到相同的,您也可以尝试这样做:

return this->parentNode != 0;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-04-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多