106 votes

Lequel est le plus rapide: si (bool) ou si (int)?

Dont la valeur est préférable d'utiliser? Boolean true ou un Entier de 1?

Le thème m'a fait faire quelques expériences avec des bool et int en if condition. Donc, juste par curiosité, j'ai écrit ce programme:

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 génère asm code pour chacune des fonctions suivantes:

  • asm code pour f(int)

    __Z1fi:
       LFB0:
             pushl  %ebp
       LCFI0:
              movl  %esp, %ebp
       LCFI1:
              cmpl  $0, 8(%ebp)
              je    L2
              movl  $99, %eax
              jmp   L3
       L2:
              movl  $-99, %eax
       L3:
              leave
       LCFI2:
              ret
    
  • asm code pour g(bool)

    __Z1gb:
       LFB1:
              pushl %ebp
       LCFI3:
              movl  %esp, %ebp
       LCFI4:
              subl  $4, %esp
       LCFI5:
              movl  8(%ebp), %eax
              movb  %al, -4(%ebp)
              cmpb  $0, -4(%ebp)
              je    L5
              movl  $99, %eax
              jmp   L6
       L5:
              movl  $-99, %eax
       L6:
              leave
       LCFI6:
              ret
    

Étonnamment, g(bool) génère plus d' asm instructions! Veut-il dire qu' if(bool) est peu plus lentement que d' if(int)? Je pensais bool est spécialement conçu pour être utilisé dans l'instruction conditionnelle telle que if, donc je m'attendais g(bool) générer moins d'instructions asm, ce qui rend g(bool) plus efficace et rapide.

EDIT:

Je ne suis pas en utilisant toute option d'optimisation à partir de maintenant. Mais même en l'absence de cela, pourquoi est-il générer plus d'asm pour g(bool) est une question pour laquelle je suis à la recherche d'une réponse raisonnable. Je dois vous dire aussi que l' -O2 optimisation drapeau génère exactement le même à l'asm. Mais ce n'est pas la question. La question est de savoir ce que j'ai demandé.


107voto

Sherm Pendley Points 10822

Fait sens pour moi. Votre compilateur définit apparemment un bool comme une valeur de 8 bits, et votre système ABI oblige à "promouvoir" petit (< 32 bits) arguments entiers de 32 bits lorsque l'on pousse sur la pile d'appel. Donc, pour comparer un bool, le compilateur génère le code pour isoler l'octet le moins significatif de l'32 bits argument que g reçoit, et le compare avec cmpb. Dans le premier exemple, l' int argument utilise l'intégralité de 32 bits qui ont été poussés sur la pile, de sorte qu'il compare simplement contre le tout avec cmpl.

85voto

Alexander Gessler Points 26717

Compilation avec -03 donne pour moi:

f:

    pushl   %ebp
    movl    %esp, %ebp
    cmpl    $1, 8(%ebp)
    popl    %ebp
    sbbl    %eax, %eax
    andb    $58, %al
    addl    $99, %eax
    ret

g:

    pushl   %ebp
    movl    %esp, %ebp
    cmpb    $1, 8(%ebp)
    popl    %ebp
    sbbl    %eax, %eax
    andb    $58, %al
    addl    $99, %eax
    ret

.. donc il compile essentiellement le même code, sauf pour cmpl vs cmpb. Cela signifie que la différence, si il y a de tout, n'a pas d'importance. À en juger par unoptimized code n'est pas juste.

Edit pour préciser mon point de vue. Unoptimized code est simple pour le débogage, pas pour la vitesse. Comparant la vitesse de unoptimized code est absurde.

27voto

Quand je compile ce avec un esprit sain ensemble d'options (O3), voici ce que j'obtiens:

Pour f():

        .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

Pour g():

        .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

Ils continuent à utiliser des instructions différentes pour la comparaison (cmpb booléenne vs cmpl int), mais sinon le corps sont identiques. Un rapide regard sur les manuels Intel me dit: ... pas grand-chose. Il n'y a pas une telle chose comme cmpb ou cmpl dans les manuels Intel. Ils sont tous cmp et je ne peux pas trouver le calendrier des tables à l'heure actuelle. Je suppose, cependant, qu'il n'y a pas d'horloge différence entre la comparaison d'un octet immédiate contre la comparaison d'une longue immédiat, donc, à toutes fins pratiques, le code est identique.


modifié pour ajouter les options suivantes en fonction de votre plus

La raison pour laquelle le code est différent dans le unoptimized cas, c'est qu'il est unoptimized. (Oui, elle est circulaire, je sais). Lorsque le compilateur promenades de l'AST et génère le code directement, il ne sait pas" n'importe quoi sauf ce qui est au point de l'AST. À ce stade, il est dépourvu de toute information contextuelle nécessaire de savoir que, à ce point précis, il peut traiter le type déclaré bool comme int. Un booléen est évidemment par défaut traitée comme un octet, et lors de la manipulation des octets dans le Intel monde que vous avez à faire des choses comme le signe-s'étendre à apporter à certaines largeurs de le mettre sur la pile, etc. (Vous ne pouvez pas pousser un octet.)

Lorsque l'optimiseur de vue de l'AST et de la magie, cependant, il ressemble au contexte environnant et "sait" quand il peut remplacer le code avec quelque chose de plus efficace sans changer la sémantique. Donc, il "sait", il peut utiliser un entier en paramètre et perdre ainsi les conversions inutiles et l'élargissement.

13voto

Mat Points 104488

Avec GCC 4.5 sous Linux et Windows au moins, sizeof(bool) == 1 . Sur x86 et x86_64, vous ne pouvez pas transférer moins de valeur qu'un registre à usage général à une fonction (via la pile ou un registre en fonction de la convention d'appel, etc.).

Ainsi, le code de bool, lorsqu'il n'est pas optimisé, prend en réalité une certaine longueur pour extraire cette valeur de bool de la pile d'arguments (en utilisant un autre emplacement de pile pour enregistrer cet octet). C'est plus compliqué que de simplement extraire une variable native de la taille d'un registre.

9voto

DigitalRoss Points 80400

Au niveau de la machine il n'y a pas une telle chose comme bool

Très peu de jeu d'instructions architectures de définir toute sorte d'opérande booléen type, bien qu'il existe souvent des instructions afin de déclencher une action sur des valeurs non nulles. Pour le PROCESSEUR, généralement, tout ce qui est l'un des types scalaires ou une chaîne de caractères.

Un compilateur et un ABI aurez besoin de choisir des tailles spécifiques pour int et bool et si, comme dans votre cas, ces sont de tailles différentes, ils peuvent générer du code légèrement différent, et à certains niveaux de l'optimisation, on peut être un peu plus rapide.

Pourquoi est-bool d'un octet sur de nombreux systèmes?

Il est plus sûr de choisir un char type bool parce que quelqu'un peut faire une très grande foule.

Mise à jour: par la"sécurité", je veux dire: pour le compilateur et de la bibliothèque des réalisateurs. Je ne dis pas que les gens ont besoin de ré-écrire le type de système.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X