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
etint
enif
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 pensaisbool
est spécialement conçu pour être utilisé dans l'instruction conditionnelle telle queif
, donc je m'attendaisg(bool)
générer moins d'instructions asm, ce qui rendg(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é.
Réponses
Trop de publicités?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
.
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.
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.
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.
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.