为什么对bool的cast指针有性能警告?

bob*_*obo 53 c++ performance casting

延伸.

当我做了类似的事情时,我以为我很酷

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

即使有(布尔)演员,警告仍然不会消失.

当没有父节点时this-> parentNode为NULL.

但是我得到了:

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

这是什么交易,哟?为什么这是表现警告?我认为不写下这样的东西会更有效率:


bool hasParent()
{
  if( this->parentNode )
    return true ;
  else
    return false ;
}

但第二个版本没有产生警告,编译器似乎更快乐.哪个更快?

Mic*_*urr 46

有关此问题的Microsoft Connect的讨论(在C++中转换为bool的性能影响是什么?).给微软的例子是:

$ 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)
Run Code Online (Sandbox Code Playgroud)

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

这个警告非常有用,昨天我的代码中发现了一个错误.我认为马丁正在脱离背景"性能警告".

它不是关于生成的代码,而是关于程序员是否发出了将值从int更改为bool的意图.对此有一个惩罚,并且用户可以选择一致地使用"int"而不是"bool"(或者更可能反之亦然)以避免"boolifying"codegen.警告在下面的第三种情况下被抑制,因为他明确表示他接受int-> bool过渡的意图.

这是一个旧的警告,可能已经超出了它的目的,但它的行为与此处的设计相同

所以基本上MS开发商似乎是说,如果你想"投"的intbool,你应该更好地被利用做" return this->parentNode != 0",而不是一个或明或暗投.

就个人而言,我有兴趣了解警告揭示的错误类型.我认为这个警告不会有很多价值.

  • bobobobo:任何理智的编译器(至少是gcc)都会对此发出警告.如果正确使用"const",hasParent()将是一个const函数,因此它将是一个编译错误. (11认同)
  • 我认为应该有一个编译器标志来启用那些无用的警告.这个和"大多数C和一些C++标准库已被弃用"警告总是让我产生一种冲动,只是在使用VC时完全禁用警告. (5认同)
  • 另外`return this-> parentNode!= 0`更容易出错,因为可能会输入错误`return this-> parentNode = 0`. (4认同)
  • 我也认为这个警告是没用的,但是我再次对MS VC有偏见;-) (3认同)
  • 它是为历史葡萄干而存在的。一些旧的非一致性编译器(可能是 VStudio v. < 5.0)只是在布尔上下文中转换为 bool,这很快。但这也是危险且不标准的(参见我的答案)。因此,他们将其更改为“!= 0”比较,这比代码生成器中之前的转换要慢。因此,这样做的人也会输出一个警告...警告旧代码库维护者客户,新编译器的某些内容会变慢。 (2认同)
  • 如果警告是为了捕获错误,那就是错误的. (2认同)

Jam*_*lis 28

铸造bool不会使警告消失的事实是设计:

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

我建议使用警告C4800建议的MSDN描述的方法:

return this->parentNode != NULL;
Run Code Online (Sandbox Code Playgroud)

这清楚地表明,true如果parentNode不是空指针并且falseif parentNode是空指针,则返回.

  • 看起来太令人兴奋了 (3认同)

Gun*_*iez 8

编译器需要生成用于将指针转换为bool的附加代码.它基本上是对零的比较,如果不是零则将结果设置为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
Run Code Online (Sandbox Code Playgroud)

这不是从源直接可见的,因此编译器认为这是用户应该被警告的内容.


use*_*876 7

为什么这是表现警告?

编译器正在转变:

bool hasParent()
{
  return this->parentNode;
}
Run Code Online (Sandbox Code Playgroud)

成:

bool hasParent()
{
  return this->parentNode != 0;
}
Run Code Online (Sandbox Code Playgroud)

这比查看代码所需的时间大约多一个时钟周期.这是一个微不足道的性能差异.

我认为最好!= 0明确地写出来,因为它使代码更清晰,同时使警告静音.

  • 哦,嗯.1个时钟周期超过3,000,000,000?那太过分了. (9认同)
  • 在某些用途中,即使1个时钟周期也很重要. (2认同)