Nommé pour la question d'entrevue la plus stupide de tous les temps. Et il y a une rude concurrence.
Konrad Rudolph
119
Vous: Nommez une situation dans laquelle la différence entre ces deux éléments pourrait valoir la peine d'être examinée. Interviewer: D'accord, vous êtes embauché.
Chris Lutz
37
La seule différence entre les deux est qu'avec la dernière convention, vous êtes assuré contre les bugs comme if(flag = 0)au prix d'un peu de lisibilité.
Amarghosh
22
@Amarghosh: Au prix de rendre votre code difficile à lire et peu intuitif. Utilisez le premier pour activer les avertissements de votre compilateur, gagnant-gagnant.
GManNickG
129
Une fois, un rédacteur compilateur a eu cela dans son interview. Il a chuchoté en réponse, "lequel voulez- vous être le plus rapide?".
Réponses:
236
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 flagle type?
Dans le cas où flagest 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 flags'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 Jxxinstruction pour la ifdé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){return0;}return1;}int yoda(int c){if(0== c){return0;}return1;}
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.
@Matthieu: vous avez dit que je n'ai pas encore vu de réponse correcte .. mais la mienne est correcte, je pense: P
Nawaz
7
bien! votre réponse possible transforme "la question la plus stupide" en "la plus délicate / la plus méchante". "creusons un trou pour le candidat et voyons s'il y tombe ..." :) Je suppose que nous supposons tous automatiquement que cela flagdoit être un entier ou un booléen. OTOH, avoir une variable nommée flagd'un type défini par l'utilisateur est tout à fait faux sur lui-même, à
mon humble avis
@Nawaz: J'ai peut-être sauté le dernier paragraphe de votre réponse: p
Matthieu M.
1
@Nawaz: Je ne fais pas vraiment de course, je lis généralement les questions longtemps après qu'on leur ait répondu et les gens ont tendance à ne lire que les premières réponses les plus votées :) Mais je lis en fait des trucs sur les optimisations du compilateur, et cela m'a frappé comme un cas typique d'optimisation triviale, j'ai donc pensé le signaler aux lecteurs qui dérangent réellement ... Je suis assez surpris en fait d'avoir eu autant de votes positifs. Maintenant, c'est ma réponse la plus votée même si ce n'est certainement pas celle dans laquelle j'ai mis le plus d'efforts: / Quoi qu'il en soit j'ai édité ma réponse et corrigé ma déclaration :)
Matthieu M.
2
@mr_eclair: un type intégré est un type qui est (comme son nom l'indique) intégré au langage. Autrement dit, il est disponible même sans #includedirective unique . Par souci de simplicité, il revient généralement int, char, boolet 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::stringest défini par l'utilisateur, même si vous ne l'avez certainement pas défini vous-même :)
Matthieu M.
56
Même code pour amd64 avec GCC 4.1.2:
.loc 140# int f = argc;
movl -20(%rbp),%eax
movl %eax,-4(%rbp).loc 160# if( f == 0 ) {
cmpl $0,-4(%rbp)
jne .L2
.loc 170# return 0;
movl $0,-36(%rbp)
jmp .L4
.loc 180# }.L2:.loc 1100# if( 0 == f ) {
cmpl $0,-4(%rbp)
jne .L5
.loc 1110# return 1;
movl $1,-36(%rbp)
jmp .L4
.loc 1120# }.L5:.loc 1140# return 2;
movl $2,-36(%rbp).L4:
movl -36(%rbp),%eax
.loc 1150# }
leave
ret
+1 pour avoir fait un effort supplémentaire pour prouver que l'optimisation du compilateur est la même.
k rey
56
Il n'y aura aucune différence dans vos versions.
Je suppose que l' typeindicateur 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!
cela pourrait être la seule raison possible de poser cette question, à
mon humble avis
15
Je serais extrêmement surpris si les compilateurs modernes manquaient une optimisation aussi évidente.
Pedro d'Aquino
3
À ma connaissance ! n'est pas une opération au niveau du bit
Xavier Combelle
8
@Nawaz: n'a pas voté contre mais votre réponse est factuellement erronée et c'est horrible qu'il y ait encore autant de votes positifs. Pour mémoire, comparer un entier à 0 est une seule instruction d'assemblage , complètement à égalité avec la négation. En fait, si le compilateur est légèrement stupide, cela pourrait même être plus rapide que la négation (peu probable cependant).
Konrad Rudolph
6
@Nawaz: il est toujours faux de dire que cela peut, sera ou sera généralement plus rapide. S'il y a une différence, alors la version "comparer à zéro" sera plus rapide, puisque la négation une se traduit vraiment en deux opérations: "nier l'opérande; vérifier que le résultat est différent de zéro". En pratique, bien sûr, le compilateur l'optimise pour donner le même code que la version simple "comparer avec zéro", mais l'optimisation est appliquée à la version de négation, pour la faire rattraper, et non l'inverse. Konrad a raison.
jalf
27
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>.
@Matthieu Huh. J'ai dû manquer le post sur meta décrivant le style de contreventement "approprié".
Linus Kleen
7
Je n'ai pas du tout voté, mais pour ce que ça vaut: pourquoi est-il si important que les gens s'expliquent chaque fois qu'ils votent? Les votes sont anonymes par conception. Je suis tout à fait opposé à l'idée que les contrevenants devraient toujours commenter, parce que personnellement, je ne veux jamais être supposé être le contrevenant simplement parce que j'ai laissé un commentaire soulignant un problème. Peut-être que l'électeur défavorable a pensé que la majorité de la réponse était sans rapport avec la question de la vitesse? Peut-être pensait-il que cela encourageait un style de codage qu'il n'approuvait pas? Peut-être était-il un con et voulait que sa propre réponse ait la meilleure note?
David Hedlund
3
Les gens devraient être libres de voter comme ils le voudront, quelle qu'en soit la raison. En ce qui concerne la réputation, c'est presque toujours une bonne chose car cela incite souvent d'autres personnes à voter pour, pour contrer le vote négatif non mérité, alors qu'en fait, un seul vote positif annulerait cinq votes négatifs non mérités.
David Hedlund
26
@David: Les downvoters devraient s'expliquer car ce site ne traite pas des bulletins de vote secrets, du vote anonyme, etc. Ce site concerne l'apprentissage. Si quelqu'un dit qu'une réponse est incorrecte en la votant défavorablement, l'électeur défavorable est égoïste avec ses connaissances s'il n'explique pas pourquoi. Ils sont prêts à prendre tout le mérite pour quand ils ont raison, mais pas prêts à partager leurs connaissances lorsque les autres ont tort.
John Dibling
1
Juste pour éliminer le problème du style vivifiant, je pense vraiment que Matthieu a voulu que ce soit une blague. Je serais surpris de voir que n'importe qui vote en fonction de ces questions. Cela dit, tout le monde n'utilise pas les votes exactement de la même manière. Je pourrais voir la raison du vote négatif parce que le message semble préconiser un style de codage que l'électeur pourrait désapprouver (notez la différence entre le fait de préconiser un style de codage - "si vous écrivez votre code comme celui-ci, vous obtiendrez une erreur de compilation lorsque vous faites cette faute de frappe "- et simplement en utilisant un style de codage, tel que des accolades) En cela ...
David Hedlund
16
Il n'y aura absolument aucune différence en termes de vitesse. Pourquoi devrait-il y en avoir?
si le compilateur a été complètement retardé. C'est la seule raison.
JeremyP
@JeremyP: Je ne peux pas imaginer une différence même si le compilateur était retardé. Le rédacteur du compilateur devrait le faire exprès pour autant que je sache.
Jon
2
En supposant que le processeur dispose d'une instruction "test if 0", il x == 0peut l'utiliser mais 0 == xpeut utiliser une comparaison normale. J'ai dit qu'il faudrait ralentir.
JeremyP
8
Si l'indicateur est un type défini par l'utilisateur avec une surcharge asymétrique de l'opérateur == ()
OrangeDog
Parce que nous pourrions avoir virtual operator==(int)dans un type défini par l'utilisateur?
lorro
12
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;}operatorint(){
std::cout <<"operator int()"<< std::endl;return wrappedInt;}booloperator==(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 fasterif(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é.
qu'est-ce qui ne va pas avec l'analyse comparative? parfois la pratique vous en dit plus que la théorie
Elzo Valugi
1
C'est la réponse que je cherchais quand j'ai commencé à lire ce fil. Il semble que la théorie soit plus attrayante que la pratique, en regardant les réponses et les votes positifs :)
Samuel Rivas
comment pourrait-il se comparer à l'entrevue? De plus, je pense que l'intervieweur ne sait même pas ce que signifie l'analyse comparative, alors il aurait pu être offensé.
IAdapter
La bonne réponse à la question (IMO) est "Cela dépend à peu près du compilateur et du reste du programme. J'écrirais un benchmark et le testerais en 5 minutes"
Samuel Rivas
7
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{}
Merci d'avoir fait écho. Notez cependant que PHP par exemple ne préviendra pas en cas d'affectations conditionnelles.
Linus Kleen
5
Comme d'autres l'ont dit, il n'y a pas de différence.
0doit être évalué. flagdoit ê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>usingnamespace std;class x {public:booloperator==(int x){ cout <<"hello\n";return0;}friendbooloperator==(int x,const x& a){ cout <<"world\n";return0;}};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 == 0pourrait compiler vers une jump if zeroinstruction d' assemblage native , alors que 0 == xpourrait ê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 ...
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.
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 ...
S'il y avait une différence, qu'est-ce qui empêche le compilateur de choisir le plus rapide une fois? Donc, logiquement, il ne peut y avoir aucune différence. C'est probablement ce que l'intervieweur attend. C'est en fait une question brillante.
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:
Dans le cas où
flag
est en fait un type défini par l'utilisateur. Ensuite, cela dépend de la surcharge de quioperator==
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 uneJxx
instruction pour laif
déclaration: peut-être unJNZ
(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)
Même si on ne sait pas lire l'IR, je pense que cela va de soi.
la source
flag
doit être un entier ou un booléen. OTOH, avoir une variable nomméeflag
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éralementint
,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:
la source
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!la source
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:
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>
.la source
Il n'y aura absolument aucune différence en termes de vitesse. Pourquoi devrait-il y en avoir?
la source
x == 0
peut l'utiliser mais0 == 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
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é.
la source
En cas de doute, comparez-le et découvrez la vérité.
la source
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é.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.
la source
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)
etif(0==flag)
ont le même nombre de caractères! Si l'un d'eux était écrit commeif(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 source
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.
la source
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 unejump if zero
instruction d' assemblage native , alors que0 == 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 ...
la source
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.
la source
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.
la source
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.
la source
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 ...
la source
S'il y avait une différence, qu'est-ce qui empêche le compilateur de choisir le plus rapide une fois? Donc, logiquement, il ne peut y avoir aucune différence. C'est probablement ce que l'intervieweur attend. C'est en fait une question brillante.
la source