Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/155.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 哪个更快:if(bool)还是if(int)?_C++_Assembly_Int_Boolean - Fatal编程技术网

C++ 哪个更快:if(bool)还是if(int)?

C++ 哪个更快:if(bool)还是if(int)?,c++,assembly,int,boolean,C++,Assembly,Int,Boolean,上面的主题让我在if条件下用bool和int做了一些实验。出于好奇,我写了这个程序: int f(int i) { if ( i ) return 99; //if(int) else return -99; } int g(bool b) { if ( b ) return 99; //if(bool) else return -99; } int main(){} g++intbool.cpp-S为每个函数生成asm代码,如下所示: f(in

上面的主题让我在
if
条件下用
bool
int
做了一些实验。出于好奇,我写了这个程序:

int f(int i) 
{
    if ( i ) return 99;   //if(int)
    else  return -99;
}
int g(bool b)
{
    if ( b ) return 99;   //if(bool)
    else  return -99;
}
int main(){}
g++intbool.cpp-S
为每个函数生成asm代码,如下所示:

  • f(int)

  • g(bool)

令人惊讶的是,
g(bool)
生成了更多的
asm
指令!这是否意味着
if(bool)
if(int)
慢一点?我曾经认为
bool
是专门设计用来在条件语句中使用的,比如
if
,所以我希望
g(bool)
生成更少的asm指令,从而使
g(bool)
更加高效和快速

编辑:

我现在没有使用任何优化标志。但是,即使没有它,为什么它会为
g(bool)
生成更多的asm,这是一个我正在寻找合理答案的问题。我还应该告诉您,
-O2
优化标志生成完全相同的asm。但这不是问题所在。这个问题就是我问的



使用
-03
编译为我提供了以下信息:

f:

g:

    pushl   %ebp
    movl    %esp, %ebp
    cmpb    $1, 8(%ebp)
    popl    %ebp
    sbbl    %eax, %eax
    andb    $58, %al
    addl    $99, %eax
    ret
。。因此它编译成基本相同的代码,除了
cmpl
vs
cmpb
。 这意味着差异,如果有的话,并不重要。根据未优化的代码进行判断是不公平的



编辑以澄清我的观点。未优化的代码用于简单调试,而不是速度。比较未优化代码的速度毫无意义。

至少在Linux和Windows上使用GCC4.5,
sizeof(bool)==1
。在x86和x86_64上,不能将少于通用寄存器的值传递给函数(无论是通过堆栈还是寄存器,取决于调用约定等)


因此,bool的代码在未优化时,实际上会经过一定的长度从参数堆栈中提取bool值(使用另一个堆栈槽保存该字节)。这比仅仅提取一个本机寄存器大小的变量要复杂得多。

对我来说很有意义。编译器显然将
bool
定义为8位值,系统ABI要求它在将小(<32位)整型参数推送到调用堆栈时将其“升级”为32位。因此,为了比较
bool
,编译器生成代码来隔离g接收的32位参数的最低有效字节,并将其与
cmpb
进行比较。在第一个示例中,
int
参数使用推送到堆栈上的全部32位,因此它只是与
cmpl

进行比较,当我使用一组合理的选项(特别是-O3)编译时,我得到了以下结果:

对于
f()

对于
g()

它们仍然使用不同的指令进行比较(
cmpb
表示布尔值,而
cmpl
表示int),但在其他方面,主体是相同的。快速浏览一下英特尔手册,我会发现:。。。什么都没有。英特尔手册中没有
cmpb
cmpl
。它们都是cmp,我现在找不到计时表。然而,我猜测,比较字节立即数和比较长立即数之间没有时钟差异,因此对于所有实际目的,代码都是相同的


编辑以根据您的添加添加以下内容

在未优化的情况下,代码不同的原因是它未优化。(是的,它是循环的,我知道。)当编译器遍历AST并直接生成代码时,除了它所在的AST的直接点之外,它什么都不“知道”。在这一点上,它缺乏所有需要了解的上下文信息,在这个特定点上,它可以将声明的类型
bool
视为
int
。显然,布尔值在默认情况下被视为字节,在英特尔世界中处理字节时,必须执行诸如“符号扩展”之类的操作,使其达到一定的宽度,以便将其放入堆栈中,等等(不能推送字节)


然而,当优化器查看AST并发挥其神奇作用时,它会查看周围的上下文并“知道”何时可以在不改变语义的情况下用更高效的代码替换代码。因此它“知道”它可以在参数中使用整数,从而丢失不必要的转换和加宽。

它将主要取决于编译器和优化。这里有一个有趣的讨论(语言不可知论):

另外,看看这篇文章:

在机器级别上没有bool这样的东西 很少有指令集体系结构定义任何类型的布尔操作数类型,尽管经常有指令触发对非零值的操作。对于CPU来说,通常,一切都是标量类型或标量类型的一个字符串

一个给定的编译器和一个给定的ABI需要为
int
bool
选择特定的大小,当这些大小不同时,它们可能会生成稍有不同的代码,并且在某些优化级别上可能会稍快一些

为什么bool在许多系统上是一个字节? 为bool选择一个
char
类型更安全,因为有人可能会创建一个非常大的数组


更新:所谓“更安全”,我的意思是:对于编译器和库实现者。我不是说人们需要重新实现系统类型。

是的,讨论很有趣。但只要测试一下:

测试代码:

#include <stdio.h>
#include <string.h>

int testi(int);
int testb(bool);
int main (int argc, char* argv[]){
  bool valb;
  int  vali;
  int loops;
  if( argc < 2 ){
    return 2;
  }
  valb = (0 != (strcmp(argv[1], "0")));
  vali = strcmp(argv[1], "0");
  printf("Arg1: %s\n", argv[1]);
  printf("BArg1: %i\n", valb ? 1 : 0);
  printf("IArg1: %i\n", vali);
  for(loops=30000000; loops>0; loops--){
    //printf("%i: %i\n", loops, testb(valb=!valb));
    printf("%i: %i\n", loops, testi(vali=!vali));
  }
  return valb;
}

int testi(int val){
  if( val ){
    return 1;
  }
  return 0;
}
int testb(bool val){
  if( val ){
    return 1;
  }
  return 0;
}
布尔测试/打印未注释(和整数注释):


在3000万个循环中,每个循环都有1个赋值和2个比较。找到其他要优化的内容。例如,不要不必要地使用strcmp

以两种不同的方式处理您的问题:

如果你是专门谈论C++的

    pushl   %ebp
    movl    %esp, %ebp
    cmpl    $1, 8(%ebp)
    popl    %ebp
    sbbl    %eax, %eax
    andb    $58, %al
    addl    $99, %eax
    ret
    pushl   %ebp
    movl    %esp, %ebp
    cmpb    $1, 8(%ebp)
    popl    %ebp
    sbbl    %eax, %eax
    andb    $58, %al
    addl    $99, %eax
    ret
        .type   _Z1fi, @function
_Z1fi:
.LFB0:
        .cfi_startproc
        .cfi_personality 0x3,__gxx_personality_v0
        cmpl    $1, %edi
        sbbl    %eax, %eax
        andb    $58, %al
        addl    $99, %eax
        ret
        .cfi_endproc
        .type   _Z1gb, @function
_Z1gb:
.LFB1:
        .cfi_startproc
        .cfi_personality 0x3,__gxx_personality_v0
        cmpb    $1, %dil
        sbbl    %eax, %eax
        andb    $58, %al
        addl    $99, %eax
        ret
        .cfi_endproc
#include <stdio.h>
#include <string.h>

int testi(int);
int testb(bool);
int main (int argc, char* argv[]){
  bool valb;
  int  vali;
  int loops;
  if( argc < 2 ){
    return 2;
  }
  valb = (0 != (strcmp(argv[1], "0")));
  vali = strcmp(argv[1], "0");
  printf("Arg1: %s\n", argv[1]);
  printf("BArg1: %i\n", valb ? 1 : 0);
  printf("IArg1: %i\n", vali);
  for(loops=30000000; loops>0; loops--){
    //printf("%i: %i\n", loops, testb(valb=!valb));
    printf("%i: %i\n", loops, testi(vali=!vali));
  }
  return valb;
}

int testi(int val){
  if( val ){
    return 1;
  }
  return 0;
}
int testb(bool val){
  if( val ){
    return 1;
  }
  return 0;
}
sauer@trogdor:/tmp$ time /tmp/test_i 1 > /dev/null

real    0m8.203s
user    0m8.170s
sys 0m0.010s
sauer@trogdor:/tmp$ time /tmp/test_i 1 > /dev/null

real    0m8.056s
user    0m8.020s
sys 0m0.000s
sauer@trogdor:/tmp$ time /tmp/test_i 1 > /dev/null

real    0m8.116s
user    0m8.100s
sys 0m0.000s
sauer@trogdor:/tmp$ time /tmp/test_i 1 > /dev/null

real    0m8.254s
user    0m8.240s
sys 0m0.000s
sauer@trogdor:/tmp$ time /tmp/test_i 1 > /dev/null

real    0m8.028s
user    0m8.000s
sys 0m0.010s
sauer@trogdor:/tmp$ time /tmp/test_i 1 > /dev/null

real    0m7.981s
user    0m7.900s
sys 0m0.050s
  mov eax,dword ptr[esp]    ;Store integer
  cmp eax,0                 ;Compare to 0
  je  false                 ;If int is 0, its false
  ;Do what has to be done when true
false:
  ;Do what has to be done when false
  mov  al,1     ;Anything that is not 0 is true
  test al,1     ;See if first bit is fliped
  jz   false    ;Not fliped, so it's false
  ;Do what has to be done when true
false:
  ;Do what has to be done when false