Question d'entrevue: lequel s'exécutera le plus rapidement, if (flag==0)
ou if (0==flag)
? Pourquoi?
if(flag = 0)
au prix d'un peu de lisibilité.
Question d'entrevue: lequel s'exécutera le plus rapidement, if (flag==0)
ou if (0==flag)
? Pourquoi?
if(flag = 0)
au prix d'un peu de lisibilité.
Réponses:
Je n'ai pas encore vu de réponse correcte (et il y en a déjà quelques-unes) mise en garde: Nawaz a souligné le piège défini par l'utilisateur . Et je regrette d'avoir voté à la hâte sur "la question la plus stupide" car il semble que beaucoup ne l'ont pas bien fait et cela laisse la place à une belle discussion sur l'optimisation du compilateur :)
La réponse est:
Quel est
flag
le type?
Dans le cas où flag
est en fait un type défini par l'utilisateur. Ensuite, cela dépend de la surcharge de qui operator==
est sélectionnée. Bien sûr, cela peut sembler stupide qu'ils ne soient pas symétriques, mais c'est certainement permis, et j'ai déjà vu d'autres abus.
S'il flag
s'agit d'un élément intégré, les deux devraient prendre la même vitesse.
De l'article de Wikipedia sur x86
, je parierais pour une Jxx
instruction pour la if
déclaration: peut-être un JNZ
(Jump if Not Zero) ou un équivalent.
Je doute que le compilateur manque une optimisation aussi évidente, même avec les optimisations désactivées. C'est le type de choses pour lequel l' optimisation du judas est conçue.
EDIT: Sprang up à nouveau, ajoutons donc un assemblage (LLVM 2.7 IR)
int regular(int c) {
if (c == 0) { return 0; }
return 1;
}
int yoda(int c) {
if (0 == c) { return 0; }
return 1;
}
define i32 @regular(i32 %c) nounwind readnone {
entry:
%not. = icmp ne i32 %c, 0 ; <i1> [#uses=1]
%.0 = zext i1 %not. to i32 ; <i32> [#uses=1]
ret i32 %.0
}
define i32 @yoda(i32 %c) nounwind readnone {
entry:
%not. = icmp ne i32 %c, 0 ; <i1> [#uses=1]
%.0 = zext i1 %not. to i32 ; <i32> [#uses=1]
ret i32 %.0
}
Même si on ne sait pas lire l'IR, je pense que cela va de soi.
flag
doit être un entier ou un booléen. OTOH, avoir une variable nommée flag
d'un type défini par l'utilisateur est tout à fait faux sur lui-même, à
#include
directive unique . Par souci de simplicité, il revient généralement int
, char
, bool
et autres. Tous les autres types sont dits définis par l' utilisateur, est qu'ils existent parce qu'ils sont le résultat d'un utilisateur en les déclarant: typedef
, enum
, struct
, class
. Par exemple, std::string
est défini par l'utilisateur, même si vous ne l'avez certainement pas défini vous-même :)
Même code pour amd64 avec GCC 4.1.2:
.loc 1 4 0 # int f = argc;
movl -20(%rbp), %eax
movl %eax, -4(%rbp)
.loc 1 6 0 # if( f == 0 ) {
cmpl $0, -4(%rbp)
jne .L2
.loc 1 7 0 # return 0;
movl $0, -36(%rbp)
jmp .L4
.loc 1 8 0 # }
.L2:
.loc 1 10 0 # if( 0 == f ) {
cmpl $0, -4(%rbp)
jne .L5
.loc 1 11 0 # return 1;
movl $1, -36(%rbp)
jmp .L4
.loc 1 12 0 # }
.L5:
.loc 1 14 0 # return 2;
movl $2, -36(%rbp)
.L4:
movl -36(%rbp), %eax
.loc 1 15 0 # }
leave
ret
Il n'y aura aucune différence dans vos versions.
Je suppose que l' type
indicateur of n'est pas un type défini par l'utilisateur, mais plutôt un type intégré. Enum est une exception! . Vous pouvez traiter enum comme s'il était intégré. En fait, les valeurs sont l'un des types intégrés!
Dans le cas, s'il s'agit d'un type défini par l'utilisateur (sauf enum
), la réponse dépend entièrement de la façon dont vous avez surchargé l'opérateur ==
. Notez que vous devez surcharger ==
en définissant deux fonctions, une pour chacune de vos versions!
Il n'y a absolument aucune différence.
Vous pourriez gagner des points en répondant à cette question d'entretien en vous référant à l'élimination des fautes de frappe d'assignation / comparaison, cependant:
if (flag = 0) // typo here
{
// code never executes
}
if (0 = flag) // typo and syntactic error -> compiler complains
{
// ...
}
Bien que ce soit vrai, par exemple, un compilateur C avertit dans le cas de l'ancien ( flag = 0
), il n'y a pas de tels avertissements en PHP, Perl ou Javascript ou <insert language here>
.
Il n'y aura absolument aucune différence en termes de vitesse. Pourquoi devrait-il y en avoir?
x == 0
peut l'utiliser mais 0 == x
peut utiliser une comparaison normale. J'ai dit qu'il faudrait ralentir.
virtual operator==(int)
dans un type défini par l'utilisateur?
Eh bien, il y a une différence lorsque l'indicateur est un type défini par l'utilisateur
struct sInt
{
sInt( int i ) : wrappedInt(i)
{
std::cout << "ctor called" << std::endl;
}
operator int()
{
std::cout << "operator int()" << std::endl;
return wrappedInt;
}
bool operator==(int nComp)
{
std::cout << "bool operator==(int nComp)" << std::endl;
return (nComp == wrappedInt);
}
int wrappedInt;
};
int
_tmain(int argc, _TCHAR* argv[])
{
sInt s(0);
//in this case this will probably be faster
if ( 0 == s )
{
std::cout << "equal" << std::endl;
}
if ( s == 0 )
{
std::cout << "equal" << std::endl;
}
}
Dans le premier cas (0 == s), l'opérateur de conversion est appelé puis le résultat renvoyé est comparé à 0. Dans le second cas, l'opérateur == est appelé.
En cas de doute, comparez-le et découvrez la vérité.
Ils devraient être exactement les mêmes en termes de vitesse.
Notez cependant que certaines personnes utilisent pour mettre la constante à gauche dans les comparaisons d'égalité (les soi-disant «conditionnelles de Yoda») pour éviter toutes les erreurs qui peuvent survenir si vous écrivez =
(opérateur d'affectation) au lieu de ==
(opérateur de comparaison d'égalité); comme l'affectation à un littéral déclenche une erreur de compilation, ce type d'erreur est évité.
if(flag=0) // <--- typo: = instead of ==; flag is now set to 0
{
// this is never executed
}
if(0=flag) // <--- compiler error, cannot assign value to literal
{
}
D'un autre côté, la plupart des gens trouvent les "conditionnels Yoda" bizarres et ennuyeux, d'autant plus que la classe d'erreurs qu'ils évitent peut être repérée également en utilisant des avertissements de compilateur adéquats.
if(flag=0) // <--- warning: assignment in conditional expression
{
}
Comme d'autres l'ont dit, il n'y a pas de différence.
0
doit être évalué. flag
doit être évalué. Ce processus prend le même temps, peu importe de quel côté ils sont placés.
La bonne réponse serait: ils ont tous les deux la même vitesse.
Même les expressions if(flag==0)
et if(0==flag)
ont le même nombre de caractères! Si l'un d'eux était écrit comme if(flag== 0)
, alors le compilateur aurait un espace supplémentaire à analyser, vous auriez donc une raison légitime de signaler le moment de la compilation.
Mais comme cela n'existe pas, il n'y a absolument aucune raison pour que l'un soit plus rapide que l'autre. S'il y a une raison, alors le compilateur fait des choses très, très étranges au code généré ...
La rapidité dépend de la version de == que vous utilisez. Voici un extrait de code qui utilise 2 implémentations possibles de ==, et selon que vous choisissez d'appeler x == 0 ou 0 == x l'un des 2 est sélectionné.
Si vous n'utilisez qu'un POD, cela ne devrait vraiment pas avoir d'importance en termes de vitesse.
#include <iostream>
using namespace std;
class x {
public:
bool operator==(int x) { cout << "hello\n"; return 0; }
friend bool operator==(int x, const x& a) { cout << "world\n"; return 0; }
};
int main()
{
x x1;
//int m = 0;
int k = (x1 == 0);
int j = (0 == x1);
}
Eh bien, je suis entièrement d'accord avec tout ce qui est dit dans les commentaires au PO, pour le plaisir de l'exercice:
Si le compilateur n'est pas assez intelligent (en fait, vous ne devriez pas l'utiliser) ou si l'optimisation est désactivée, x == 0
pourrait compiler vers une jump if zero
instruction d' assemblage native , alors que 0 == x
pourrait être une comparaison plus générique (et coûteuse) de valeurs numériques.
Pourtant, je n'aimerais pas travailler pour un patron qui pense en ces termes ...
Sûrement aucune différence en termes de vitesse d'exécution. La condition doit être évaluée dans les deux cas de la même manière.
Je pense que la meilleure réponse est "dans quelle langue est cet exemple"?
La question ne spécifiait pas le langage et elle était étiquetée à la fois «C» et «C ++». Une réponse précise nécessite plus d'informations.
C'est une question de programmation moche, mais cela pourrait être un bon dans le département sournois «donnons à l'interviewé assez de corde pour se pendre ou construire une balançoire». Le problème avec ce genre de questions est qu'elles sont généralement écrites et transmises d'un intervieweur à l'autre jusqu'à ce qu'elles atteignent des personnes qui ne la comprennent pas vraiment sous tous les angles.
Construisez deux programmes simples en utilisant les méthodes suggérées.
Assemblez les codes. Regardez l'assemblage et vous pouvez juger, mais je doute qu'il y ait une différence!
Les entretiens sont plus bas que jamais.
Juste à part (je pense en fait que tout compilateur décent rendra cette question sans objet, car il l'optimisera) en utilisant 0 == flag sur flag == 0 empêche la faute de frappe où vous oubliez l'un des = (c'est-à-dire si vous tapez accidentellement flag = 0, il compilera, mais 0 = drapeau ne le sera pas), ce qui, je pense, est une erreur que tout le monde a commise à un moment ou à un autre ...