Ce qui est plus rapide: while(1) ou de tout(2)?
C'était une interview à la question posée par un senior manager.
Qui est le plus rapide?
while(1) {
//Some code
}
ou
while(2) {
//Some code
}
J'ai dit que les deux ont la même vitesse d'exécution, comme l'expression à l'intérieur de while
faut enfin évaluer à true
ou false
. Dans ce cas, à la fois d'évaluer la true
et il n'y a pas extra instructions conditionnelles à l'intérieur de la while
condition. Ainsi, les deux auront la même vitesse d'exécution et je préfère tout (1).
Mais l'enquêteur a dit avec confiance:
"Vérifiez vos bases. while(1)
est plus rapide que while(2)
."
(Il n'était pas test ma confiance)
Est-ce vrai?
Voir aussi: Est "for(;;)" plus rapide que le "while (TRUE)"? Si non, pourquoi les utiliser?
- Une demi-décent compilateur d'optimiser à la fois les formes à rien.
- Dans optimisé la construction de tout alors que(n), n != 0 ou for(;;) sera traduit de l'Assemblée boucle sans fin avec l'étiquette de début et de goto dans la fin. Exactement le même code, la même performance.
- Pas étonnant, un stock d'optimiser apporte
0x100000f90: jmp 0x100000f90
(adresse varie, évidemment) pour les deux extraits. L'intervieweur probablement couvert sur un registre de test par rapport à un simple pavillon de saut. À la fois la question, et leur supposition, est boiteux. - Cette question de l'intervieweur tombe sous les mêmes auspices que dilbert.com/strips/comic/1995-11-17 - vous allez rencontrer quelqu'un qui croit fondamentalement ce qu'ils sont en train de dire quel que soit le quotient de la stupidité dans leur déclaration. Simplement choisissez parmi les options suivantes: une profonde breat, de jurer, de rire, de pleurer, une combinaison de ce qui précède 🙂
- W: on peut se demander ce qu'est un compilateur doit faire: traduire un Arrêt de déclaration, ou de considérer que la boucle s'arrête après un temps infini et optimiser loin l'infini de retard ?
- Apparemment, les compilateurs sont autorisés à optimiser disparaître complètement (voir ce c++ question ou cette discussion - de la recherche pour "C1X" pour un devis de la Norme), et certains compilateurs vraiment le faire (le dernier lien mentionne lesquels).
- alors, comment expliquez-vous que -1 est plus lent que 0?
- La question ne demande pas qui parcourt plus rapidement au moment de l'exécution, ou qui compile en un temps plus court. Il demande simplement à ce qui est plus rapide. Par conséquent, celui qui est premier est clairement le plus rapide des deux choix; ainsi, alors que(1) doit être plus rapide. DUH
- Peut-être qu'ils étaient à la recherche pour vous de préciser si elles étaient à la recherche pour compiler vs temps d'exécution. Je ne suis pas certain qu'ils vont avoir le même temps de compilation, que j'ai pu voir certains compilateurs avoir un début de "while(1)" et "while(true)" et sinon, de le transmettre à un plus générique const-évaluateur d'expression.
- Comme @MooseBoys mentionne. Ma première pensée a été également qu'il peut être de parler de temps de construction plutôt que de courir de temps. Ce serait bien si ceci pourrait être étudié en quelque sorte.
- Cette question est peut-être juste pour attirer les votes, mais c'est justement de sujet pour Stack Overflow.
- Mike W: Non, il allait laisser les boucles intacte. Le compilateur ne doit pas changer le sens du programme. Si le programme n'est pas arrêter, il doit rester de cette façon.
- Je pense que c'est plus rapide à écrire
while(1)
que de l'écrirewhile(2)
. Il se trouve que je viens de commander une nouvelle mécanique crayon hors de Amazon. Je vais courir quelques repères dès qu'il arrive. - L'examinateur était mort incorrect, le plus rapide est sans aucun doute
while (0)
😉 - Cette question était tout plagié sur Quora: quora.com/Programming-Which-is-faster-while-1-or-while-2
- C'est une vieille question, mais pour les futurs enquêteurs là:
while (42) { ... }
est certainement le plus lent, en vertu de tout niveau d'optimisation, avec un compilateur. Et effectivement,return 42;
s'exécute plus lentement que le renvoi de toute autre valeur. Après tout... en Fait, sur une note plus sérieuse, si j'ai vraiment fait voirwhile (42)
je voudrais savoir exactement ce que l'auteur a été de penser, et d'être en mesure de passer tout de suite de trop. - Vous devriez toujours demander pourquoi, lorsque vous rencontrez ce genre de chose. Il y a beaucoup de désinformation là-bas, et les enquêteurs ne sont pas à l'abri. L'intervieweur est mort à plat de mal dans ce cas. Compilateur écrivain parle ici. Il est aussi un peu stupide question d'entrevue: quelle différence cela fait-il dans la pratique? Qui se passe vraiment à écrire
while (2)
? Juste une occasion pour l'interviewer pour montrer son ignorance.
Vous devez vous connecter pour publier un commentaire.
Les deux boucles sont infinies, mais nous pouvons voir que l'on prend plus d'instructions/ressources par itération.
À l'aide de gcc, j'ai compilé les deux programmes suivants à l'assemblée, à divers niveaux d'optimisation:
Même sans les optimisations (
-O0
), l'assembly généré est identique pour les deux programmes. Par conséquent, il n'y a pas de différence de vitesse entre les deux boucles.Pour référence, voici l'assembly généré (à l'aide de
gcc main.c -S -masm=intel
avec une option d'optimisation):Avec
-O0
:Avec
-O1
:Avec
-O2
et-O3
(même résultat):En fait, l'assembly généré par la boucle est identique pour tous les niveaux d'optimisation:
L'important bits:
Je ne peux pas lire l'assemblée très bien, mais c'est évidemment une inconditionnelle de la boucle. Le
jmp
instruction inconditionnellement réinitialise le programme de retour à la.L2
étiquette sans même comparer une valeur à l'encontre du vrai, et bien sûr immédiatement fait à nouveau jusqu'à ce que le programme est en quelque sorte terminé. Cela correspond directement du code C/C++:Edit:
Assez intéressant, même avec pas optimisations, les boucles suivantes, qui sont toutes produites exactement la même sortie (inconditionnel
jmp
) dans l'assemblée:Et même à mon grand étonnement:
Les choses deviennent un peu plus intéressantes, avec des fonctions définies par l'utilisateur:
À
-O0
, ces deux exemples fait appelx
et d'effectuer une comparaison pour chaque itération.Premier exemple (retour 1):
Deuxième exemple (de retour
sqrt(7)
):Cependant, à
-O1
et au-dessus, ils produisent la même assemblée que les exemples précédents (une inconditionnelle de lajmp
retour à la précédente étiquette).TL;DR
En vertu de la GCC, les différentes boucles sont compilés à l'identique de l'assemblée. Le compilateur évalue les valeurs de constante et n'a pas pris la peine d'effectuer toute comparaison réelle.
La morale de l'histoire est:
-O
niveau.jmp
vers le début ou la suppression de la boucle complètement.inline
l'utilisateur de votre fonction....seh_endproc
et.ident "GCC: (tdm64-2) 4.8.1"
ne font pas partie de l'assemblée de la langue pour la boucle. La première de ces marques à la fin de la fonction, et le second, commente le fichier objet avec l'identité du compilateur qui l'a créé. (Normalement, il y aurait une fonction "épilogue", la compensation de la frame de pile et la délivrance d'unret
instruction, entre la boucle et le.seh_endproc
, mais le compilateur a réalisé que le contrôle ne sera jamais franchir la boucle infinie, et donc a omis comme inutile.)so measuring their "speed" is a bit nonsensical
, vous avez appelé?break
états), mais je l'ai juste testé de toute façon et non, même avec le code à l'intérieur de la boucle, le saut est absolue et inconditionnelle pour les deuxwhile(1)
etwhile(2)
. N'hésitez pas à tester les autres, vous-même si vous êtes réellement intéressé.cmp eax, 0
(ou la machine locale est l'équivalent de "le résultat est égal à zéro"), comme le préféré de l'algorithme, et l'analyse avancée (optimisations) sera presque certainement produire une inconditionnelle de la sauter. La cote d'un compilateur de faire quelque chose d'autre semble pratiquement absurde, puisque c'est la méthode la plus simple de mise en œuvre de tests.gcc -O0
ne veut pas vraiment dire aucun optimisations. Cela signifie juste que le minimum nécessaire pour produire braindead debugable code, toujours en passant par toutes les représentations intermédiaires gcc utilise en interne. Faire encore pire que le code-O0
qui ressemble plus à une traduction littérale de la source n'est pas une fonctionnalité quelqu'un a déjà mis en œuvre. L'objectif pour-O0
est de compiler rapidement et de rendre le code, vous pouvez toujours en une seule étape, ligne par ligne dans un débogueur.-Og
est similaire: optimiser pour le débogage.gcc
ils devraient avoir demandé la version est plus rapide sur mon compilateur.Oui,
while(1)
est beaucoup plus rapide quewhile(2)
, pour un être humain de lire! Si je voiswhile(1)
dans l'inconnu de la base de code, je sais immédiatement ce que l'auteur veut, et mes globes oculaires peuvent continuer à la ligne suivante.Si je vois
while(2)
, je vais probablement arrêter dans mon élan et essayer de comprendre pourquoi l'auteur n'a pas écritwhile(1)
. L'auteur du doigt glisser sur le clavier? Ne les responsables de ce code utiliserwhile(n)
comme un obscur commentant le mécanisme pour faire des boucles de l'air différent? C'est un brut de solution de contournement pour une fausse alerte dans certains brisé outil d'analyse statique? Ou est-ce une idée de ce que je suis en train de lire le code généré? Est-ce un bug résultant d'une mauvaise trouvez et remplacez-la totalité ou d'une mauvaise fusion, ou d'un rayon cosmique? Peut-être que cette ligne de code est censé faire quelque chose de radicalement différent. Peut-être qu'il était censé lirewhile(w)
ouwhile(x2)
. Je ferais mieux de trouver l'auteur dans le fichier de l'histoire et de leur envoyer un "WTF" e-mail... et maintenant, j'ai rompu mon mental contexte. Lewhile(2)
peut consommer plusieurs minutes de mon temps, quandwhile(1)
aurait pris une fraction de seconde!J'exagère, mais seulement un peu. La lisibilité du Code est vraiment important. Et qui vaut la peine de mentionner, dans une interview!
svn-annotate
ougit blame
(ou autre) sera utilisé ici, et en général il prend quelques minutes pour charger un fichier de blâmer l'histoire. Puis vient enfin de décider "ah, je comprends, l'auteur a écrit cette ligne, fraîchement sorti de l'école secondaire", vient de perdre 10 minutes...1
.while (2)
. La lisibilité du Code ma joue gauche ... pour qui écrirewhile (true)
. (Et je suis très triste pour Bogdan.)while(l)
ressemble beaucoup àwhile(1)
... Même innocent prospectives peuvent masquer subtile de bugs.while(2)
dans le code (en bas à considérer "les responsables de ce code utiliser while(n) comme un obscur commentant le mécanisme pour faire des boucles de l'air différent?"). Donc non, vous n'êtes pas exagérer!emacs
par exemple ne pas utiliser une couleur différente pour les nombres et les variables par défaut.qemacs
n'en soit pas une, et ma colorisation des choix un peu différent nuance de vert pour des variables et des nombres, qui ne permet pas de résoudre l'ambiguïté. Les messages d'erreur ne sont pas toujours colorisée soit. À l'aide d'équivoque noms résout le problème en toutes circonstances.for(;;)
, qui ne nécessite pas de<stdbool.h>
Les questions /réponses indiquant le code généré par un compilateur pour une cible particulière, avec un certain ensemble d'options ne répondent pas complètement à la question-à moins que la question a été posée dans ce contexte spécifique ("ce Qui est plus rapide en utilisant gcc 4.7.2 pour x86_64 avec les options par défaut?", pour exemple).
Autant que la définition du langage, dans la machine abstraite
while (1)
évalue la constante entière1
, etwhile (2)
évalue la constante entière2
; dans les deux cas, le résultat est comparé pour l'égalité à zéro. La langue standard ne dit absolument rien sur la performance relative des deux constructions.Je peux imaginer qu'une très naïf compilateur peut générer du code machine pour les deux formes, au moins lorsqu'il est compilé sans en demander l'optimisation.
D'autre part, les compilateurs C ne doit absolument évaluer certains expressions constantes au moment de la compilation, lorsqu'ils apparaissent dans des contextes qui nécessitent une expression constante. Par exemple, ceci:
nécessite un diagnostic, un paresseux compilateur n'a pas la possibilité de différer l'évaluation de
2+2
jusqu'à ce que le temps d'exécution. Depuis un compilateur doit avoir la capacité d'évaluer des expressions constantes au moment de la compilation, il n'y a aucune bonne raison de ne pas profiter de cette possibilité, même quand il n'est pas nécessaire.Le C standard (N1570 6.8.5p4) dit que
Donc pertinentes des expressions constantes sont
1 == 0
et2 == 0
, qui s'évaluer à l'int
valeur0
. (Ces comparaisons sont implicites dans la sémantique de lawhile
boucle; ils n'existent pas en tant que réel C expressions.)Une perverse naïf compilateur pourrait générer un code différent pour les deux constructions. Par exemple, pour la première elle pourrait générer une inconditionnelle de la boucle infinie (traitement de
1
est un cas particulier), et pour le second, il pourrait générer explicite au moment de l'exécution de comparaison équivalente à2 != 0
. Mais je n'ai jamais rencontré un compilateur C qui serait effectivement se comporter de cette façon, et je doute sérieusement qu'un tel compilateur existe.La plupart des compilateurs (je suis tenté de dire que l'ensemble de la production-de la qualité des compilateurs) ont des options à la demande des optimisations supplémentaires. En vertu de cette option, c'est encore moins probable qu'un compilateur de générer un code différent pour les deux formes.
Si votre compilateur génère un code différent pour les deux constructions, vérifiez d'abord que les différentes séquences de code en fait ont des performances différentes. S'ils le font, essayez de compiler à nouveau avec une option d'optimisation (si disponible). Si elles diffèrent, faire un rapport de bogue pour le fournisseur de compilateur. Ce n'est pas (nécessairement) un bug dans le sens d'une non conformité à la norme C, mais il est presque certainement un problème qui doit être corrigé.
Ligne du bas:
while (1)
etwhile(2)
presque certainement avoir les mêmes performances. Ils ont exactement la même sémantique, et il n'y a aucune bonne raison pour n'importe quel compilateur de ne pas générer de code identique.Et si il est parfaitement légal pour un compilateur de générer plus rapidement le code pour
while(1)
que pourwhile(2)
, il est tout aussi légal pour un compilateur de générer plus rapidement le code pourwhile(1)
que pour une autre occurrence dewhile(1)
dans le même programme.(Il y a une autre question implicite dans l'un vous demande: Comment faites-vous face avec un enquêteur qui insiste sur une mauvaise technique. Ce serait sans doute une bonne question pour le lieu de Travail).
while
doit être de type scalaire et le corps de la boucle est répétée jusqu'à ce que l'expression compare égal à 0. Cela ne veut pas dire qu'il n'y est impliciteexpr != 0
qui est évalué ... qui obligerait le résultat de cette -- 0 ou 1 -- être à son tour par rapport à 0, à l'infini. Non, l'expression n'est par rapport à 0, mais cette comparaison ne produit pas de valeur. P. S. je upvoted.<expr> == 0
; qu'est ce que "compare égal à 0" moyen en C. Cette comparaison est une partie de la sémantique de lawhile
boucle. Il n'y a pas d'implication, soit dans la norme ou dans ma réponse, que le résultat doit être comparé à0
de nouveau. (Je l'aurais écrit==
plutôt que!=
.) Mais cette partie de ma réponse n'était pas claire, et je vais le mettre à jour.while (2)
,while (pointer)
,while (9.67)
, par le plus naïf, unoptimized compilateur, vous ne verrez pas de code généré des rendements0
ou1
. "Je l'aurais écrit == plutôt que !=" -- non, cela n'aurait pas fait sens.... == 0
C expression. Mon point est que les deux "compare égal à 0" requis par la norme de description dewhile
boucles et explicitex == 0
expression impliquent logiquement la même opération. Et je pense que un douloureusement naïf C compilateur peut générer du code qui génère uneint
valeur de0
ou1
pour toutwhile
boucle -- bien que je ne crois pas que le compilateur réel est tout à fait naïf.int main(void){while (1){}}
est bien défini; il n'a pas d'effets secondaires et ne s'arrête pas.int shouldHang; while(1) if (!shouldHang) break;
différente dewhile(shouldHang);
[reconnaissant que, dans les deux cas, sishouldHang
est observée vrai, une fois, un compilateur serait soumis à aucune obligation de préavis, si sa valeur est de l'extérieur modifiée]. Aussi, est-il rien qui précise que "en supposant que la boucle s'arrête" est équivalent à "en supposant que la boucle s'arrête pour une raison quelconque admis par la norme"? Que penseriez-vous de ma proposition de règle ou de précisions?Attendez une minute. L'interviewer, avait-il ressembler à ce mec?
Il est assez mauvais que l'enquêteur lui-même a échoué cette interview,
que faire si d'autres programmeurs à ce société de "faire passer" ce test?
Pas. Évaluer les déclarations
1 == 0
et2 == 0
devrait être tout aussi rapide. Nous pourrait imaginer pauvres compilateur implémentations où l'on peut être plus rapide que les autres. Mais il n'y a pas bonne raison pour laquelle on devrait être plus rapide que l'autre.Même si il y a un peu obscures circonstances où la réclamation serait vrai, les programmeurs ne doit pas être évaluée en se basant sur la connaissance de l'obscur (et dans ce cas, flippant) de trivia. Ne vous inquiétez pas au sujet de cette entrevue, le meilleur choix ici est à pied.
Avertissement: Ce n'est PAS un original de bande dessinée Dilbert. Ce n'est qu'un mashup.
cmp
opérande exécuter en moins de cycles de la comparaison de 1 à 0 de 2 à 0 ? combien de cycles faut-il pour exécuter cmp en général ? est-il variable selon les modèles de bits ? sont-ils plus "complexe" modèles de bits qui ralentissentcmp
? Je ne connais pas personnellement. on pourrait imaginer un super idiot de mise en œuvre de la vérification, bit par bit de rang 0 à n (par exemple n=31).cmp
opérande doit être aussi rapide pour 1 et 200. Probablement que nous pourrait imaginer idiot implémentations où ce n'est pas le cas. Mais peut-on imaginer un non idiot mise en œuvre oùwhile(1)
est plus rapide quewhile(200)
? De même, si dans certains pré-historique de l'âge, de la seule mise en œuvre était idiot comme ça, devrions-nous l'histoire aujourd'hui? Je ne le pense pas, c'est pointu à poil entretien de patron, et l'un des joyaux à ce!Votre explication est correcte. Cela semble être une question qui teste votre confiance en soi en plus de connaissances techniques.
Par ailleurs, si vous avez répondu
l'intervieweur dire
Donc par répondre comme vous l'avez fait, vous avez économisé un peu de temps dont vous auriez autrement des déchets sur l'examen de cette question.
Voici un exemple de code généré par le compilateur sur mon système (MS Visual Studio 2012), avec les optimisations éteint:
Avec les optimisations activée:
De sorte que le code généré est exactement le même, au moins avec un compilateur optimisant.
cmp eax, 1 (or 2, depending on your code)
- qui n'est pas entièrement vrai. L'opérande pourwhile
est de type booléen, donc qu'il ne correspond pas complètement à l'opération sur des nombres entiers dans l'assemblée (même si elle peut, aussi longtemps que la sémantique est préservée).while (some boolean value)
logique. Votre compilateur peut choisir cette mise en œuvre, s'il conserve le fucntionalitywhile
longtemps précédé) et l'opérande dewhile
n'est pas de booléen ou _Bool ou de tout autre type spécifique. L'opérande dewhile
peut être aucun expression ... le tout se brise sur 0 et continue sur la non-0.while (00000001) {}
àwhile (00000000) {}
. Le plus vrai bits que vous avez le moins de chance de la valeur de retournement de faux. Malheureusement, 2 n'a qu'un seul vrai bits. 3, cependant, serait pour beaucoup plus longtemps. Cela ne s'applique à un compilateur, ce qui n'est pas toujours d'optimiser cette distance (VC++).cmp
opération ? personne n'a dit qu'il avait une constante de temps d'exécution quelle que soit la valeur de l'opérande pour l'instant. Vous avez à dire, et de le prouver, ALORS votre argument serait fini. Les compilateurs sont une chose, c'est très important, mais l'histoire ne s'arrête pas là tout de suite._Bool
. Il n'est pas défini dans<stdbool.h>
, c'est prédéfinie commeint
est.<stdbool.h>
définitbool
comme un alias pour_Bool
. D'autre part, de l'égalité et de comparaison les opérateurs de produire des résultats de typeint
, pas de type_Bool
-- mais je ne dirais pas que les causes_Bool
de ne pas être un type booléen.L'explication la plus probable de la question est que le journaliste pense que le processeur vérifie que les bits des nombres, un par un, jusqu'à ce qu'il frappe une valeur non nulle:
Si l' "est égal à zéro?" algorithme commence à partir de la droite du nombre et de vérifier chaque morceau jusqu'à ce qu'il atteint zéro, les bits, les
while(1) { }
boucle aurait pour vérifier deux fois plus de bits par itération que l'while(2) { }
boucle.Cela nécessite un très mauvais modèle mental de la façon dont les ordinateurs fonctionnent, mais il a sa propre logique interne. Une façon de vérifier serait de demander si
while(-1) { }
ouwhile(3) { }
serait tout aussi rapide, ou siwhile(32) { }
serait encore plus lente.cmp
algorithme d'un PROCESSEUR est un linéaire de contrôle de bit, avec un début de sortie de boucle sur la première différence.while(1)
(et peut-êtrewhile(42)
) comme infini-boucle d'idiomes, pas le cas général d'une non-zéro constante à la compilation.1
, qui est hilarant. Mais encore l'égalité de la taille du code et de la vitesse d'exécution pour les deux. Dépendant des données temps d'exécution sont très rares sur n'importe quel CPU pour le commun des instructions simples. C'est le cas pour des instructions complexes (commediv
. Dans certains Processeurs, peut-êtremul
.) lente mais constante de temps est commun dans certaines conceptions, dépendant des données n'est pas. (esp. en dehors de l'ordre de Processeurs, de la planification est dur avec latence variable.)while(1) { }
à unjmp
au bas de la boucle. Mais chaque déclaration encore compilées à un bloc contigu de l'asm. Comme vous pouvez le voir sur le Compilateur de l'Explorateur de couleur de la surbrillance (godbolt.org/z/Xoegb4) les instructions sont toujours appariés à des blocs de l'asm dans un façon saine. En essayant de définir un point d'arrêt sur lawhile(1)
lui-même vous donnera le haut de la boucle, ce qui est bien.while(1)
n'est pas une condition à tous, il vient de est une inconditionnelle de la boucle. De la même façon les programmeurs de le regarder. Cela ne prend pas l'asm à mettre en œuvre, autre que la boucle de la branche.std::log10
ou d'autres fonctions mathématiques commeconstexpr
dans MSVC). Si vous voulez une libération efficace, vous n'allez pas le compiler en mode de débogage, de toute façon.volatile
accès doivent vraiment se passer comme à l'écrit. Le fait que les données des courses sur des non-atomique variables sont UB (dans le C11 modèle de mémoire) signifie que même l'ordre de l'évolution des variables globales ne compte pas "observables".-O0
de sortie n'est pas assez littérale. Et fait amusant: gcc même des optimisations comme Pourquoi ne GCC utilisent la multiplication par un nombre étrange dans la mise en œuvre de division entière? au -O0 quand il est dans un état unique. voir, par exemple, Pourquoi la division entière par -1 (négatif) résultat de la FPE?. Et BTW, le débogage en mode performance est parfois pertinent pour les jeux ou d'autres choses qui en temps réel les exigences pour être utilisable à tous.-O0
de sortie n'est pas assez littérale." Je n'ai jamais dit une telle chose et je n'ai pas de gcc ou clang dans l'esprit à tous. Vous devez être erreur de lecture, moi. Je ne suis pas de votre avis que MSVC produit est hilarant.while (1)
optimisé loin, même alors. Cependant, il y a une véritable différence entre les deux points d'arrêt mis à la pendant et immédiatement après la{
l'intérieur de la boucle, au moins dans MSVC. La première sera de briser une seule fois, avant l'entrée dans la boucle et l'autre au début à chaque itération, ce qui peut être important lorsque la boucle de contenu n'est pas trivial. Et si vous activez les optimisations pour le débogage, le premier point d'arrêt sera disparu. Il n'est pas besoin pour être aussi complexe que cela, mais il peut aider.gcc -g -O0
, si vous utiliser GDB pour définir un point d'arrêt sur lawhile(1)
ligne il s'applique en fait à la première ligne du corps de la boucle. Mais un point d'arrêt sur lawhile(x)
est effectivement juste avant de la boucle. En asm, c'est une pause sur l'adresse de l'jmp
avant la boucle appropriée qui saute de la condition de la boucle du bas. (Pourquoi boucles toujours compilé dans "do...while" style " (queue de saut)?). Je suis curieux de ce que l'adresse de MSVC allait se briser sur.while(1)
ne fait pas de pause avant la boucle, mais sur l'expression. Mais encore, elle s'effondre à l'intérieur de la boucle lors de l'optimisation de l'expression à l'écart. Prendre ce code avec de nombreuses pauses. Dans unoptimized mode de débogage, vous obtenez ceci. Lors de l'optimisation, de nombreux points d'arrêt automne ou même des répercussions sur la fonction suivante (l'IDE montre le résultat des points d'arrêt lors du débogage) - correspondant démontage.Bien sûr, je ne connais pas les intentions réelles de ce gestionnaire, mais je propose une vision complètement différente: Lors de l'embauche d'un nouveau membre dans une équipe, il est utile de savoir comment il réagit à des situations de conflit.
Ils vous ont poussé dans le conflit. Si cela est vrai, ils sont intelligents et que la question est bonne. Pour certaines industries, comme les services bancaires, de poster votre problème de Pile Overflow pourrait être un motif de rejet.
Mais bien sûr, je ne sais pas, je viens de proposer une option.
Je pense que l'indice se trouve dans "demandé par un senior manager". Cette personne évidemment cessé de programmation lorsqu'il est devenu directeur et puis il a fallu lui plusieurs années pour devenir un gestionnaire principal. Jamais perdu l'intérêt dans la programmation, mais n'a jamais écrit une ligne depuis ces jours. Donc sa référence n'est pas "tout compilateur décent là-bas" que certaines réponses mentionnent, mais "le compilateur cette personne a travaillé avec de 20 à 30 ans".
À cette époque, les programmeurs ont passé une partie considérable de leur temps à essayer différentes méthodes pour faire de leur code plus rapide et plus efficace que le temps CPU de la "centrale d'un mini ordinateur" était tellement précieuses. Comme l'ont fait les gens de l'écriture de compilateurs. Je suppose que le seul compilateur sa société disponibles à l'époque optimisé sur la base de la "rencontre fréquemment des déclarations qui peuvent être optimisés" et a pris un peu un raccourci lors de la rencontre d'un certain temps(1) et de les évaluer tout le reste, y compris un certain temps(2). Ayant eu une telle expérience pourrait expliquer sa position et sa confiance en elle.
La meilleure approche pour obtenir que vous avez embauché est probablement celui qui permet au senior manager de se laisser emporter et la leçon de 2-3 minutes sur "le bon vieux temps de la programmation" avant de VOUS douceur le conduire vers la prochaine entrevue sujet. (Bon timing est important ici - trop vite et vous êtes interrompre l'histoire - trop lent et que vous êtes étiqueté comme quelqu'un avec attention insuffisante). Ne lui dis à la fin de l'entrevue que vous serais très intéressé d'en apprendre plus sur ce sujet.
Vous devriez lui ai demandé comment était-il parvenu à cette conclusion. En vertu de tout bon compilateur là, les deux compiler à la même asm instructions. Donc, il devrait vous ai dit que le compilateur pour commencer. Et même alors, vous devez connaître le compilateur et de plate-forme très bien à même de faire une partie théorique d'une hypothèse. Et à la fin, il n'a pas vraiment d'importance dans la pratique, puisqu'il existe d'autres facteurs externes comme la fragmentation de la mémoire ou de la charge du système, qui aura une influence sur la boucle de plus de ce détail.
Pour le bien de cette question, je dois ajouter que je me souviens de Doug Gwyn à partir de C Comité de rédaction que certains des premiers compilateurs C sans l'optimiseur de passer permettrait de générer un test de l'assemblée de la
while(1)
(en comparant àfor(;;)
qui ne l'ont pas).Je voudrais répondre à l'enquêteur en donnant cette note historique et ensuite de dire que même si je serais très surpris n'importe quel compilateur l'a fait, un compilateur pourrait avoir:
while(1)
etwhile(2)
while(1)
parce qu'ils sont considérés comme idiomatiques. Cela laisserait lewhile(2)
avec un test et en fait donc une différence de performance entre les deux.Je serais bien sûr ajouter à l'intervieweur que n'envisage pas
while(1)
etwhile(2)
la même construction est un signe de faible-l'optimisation de la qualité que ce sont les équivalents des constructions.Une autre prise sur une telle question serait de voir si vous avez le courage de dire à votre gestionnaire qu'il/qu'elle est fausse! Et comment doucement, vous pouvez la communiquer.
Mon premier réflexe aurait été de générer de l'assemblée de sortie pour afficher le gestionnaire de tout bon compilateur doit prendre soin d'elle, et si elle n'est pas ainsi, vous allez vous présenter le prochain patch pour elle 🙂
De voir tant de gens se plonger dans ce problème, montre exactement pourquoi cela pourrait très bien être un test pour voir combien de temps vous voulez micro-optimiser choses.
Ma réponse serait; il n'a pas beaucoup d'importance, j'ai plutôt l'accent sur le problème de l'entreprise qui nous sont les problèmes. Après tout, c'est ce que je vais être payé pour.
De plus, j'opterais pour
while(1) {}
parce qu'il est plus commun, et d'autres coéquipiers n'aurait pas besoin de passer du temps à comprendre pourquoi quelqu'un ferait pour un nombre plus élevé que 1.Allez maintenant écrire le code. 😉
Si vous êtes inquiet au sujet de l'optimisation, vous devez utiliser
car qui n'a pas de tests. (cynique) de mode
while(2)
, il laisse de la place pour l'optimisation, il vous suffit de passer àfor (;;)
lorsque vous êtes prêt pour un gain de performance.Il me semble que c'est l'une de ces questions d'entrevue comportementales masqué sous la forme d'une question technique. Certaines entreprises ne sont - elles se posera une question technique qui devrait être assez facile pour n'importe quel programmeur compétent pour répondre, mais lorsque la personne interrogée donne la bonne réponse, l'enquêteur va leur dire qu'ils sont mauvais.
La société veut voir comment vous allez réagir dans cette situation. Vous êtes-vous assis là tranquillement et ne poussez pas que votre réponse est correcte, en raison soit de doute de soi ou la peur de déplaire à l'interviewer? Ou êtes-vous prêt à défier une personne en autorité qui tu sais, c'est mal? Ils veulent voir si vous êtes prêts à défendre vos convictions, et si vous pouvez le faire dans un de tact et de respect.
J'ai utilisé pour programmer en C et assembleur de retour quand ce genre de non-sens aurait peut-être fait une différence. Quand il a fait faire une différence, nous l'avons écrit dans l'Assemblée.
Si je pose cette question, j'aurais répété Donald Knuth célèbre de 1974 à propos de l'optimisation prématurée et marcha si l'interviewer n'a pas de rire et de se déplacer sur.
Peut-être l'intervieweur pose une telle question stupide intentionnellement et je voulais vous faire 3 points:
Voici un problème: Si vous écrivez un programme et de mesurer sa vitesse, la vitesse de chacune des deux boucles pourrait être différent! Pour certains comparaison raisonnable:
avec un peu de code ajouté que les estampes de l'époque, certains des effets aléatoires, comme la façon dont la boucle est placée à l'intérieur d'une ou deux lignes de cache pourrait faire une différence. Une boucle peut par hasard être entièrement à l'intérieur d'une ligne de cache, ou au début d'une ligne de cache, ou à cheval sur deux lignes de cache. Et ainsi, quelle que soit l'interviewer revendications est plus rapide pourrait en fait être plus rapide qu'une coïncidence.
Pire des cas: Une optimisation du compilateur n'est pas à comprendre ce que la boucle n', mais les chiffres que les valeurs produites lors de la deuxième boucle est exécutée sont les mêmes que produite par la première. Et de générer le code complet pour la première boucle, mais pas pour le second.
Ils sont tous les deux égaux - même.
Selon les spécifications de tout ce qui n'est pas 0 est considérée comme vraie, de sorte que même sans aucune optimisation, et un bon compilateur ne génère aucun code
pour tout(1) ou de tout(2). Le compilateur génère une simple case pour
!= 0
.À en juger par la quantité de temps et d'effort gens qui ont passé des tests, ce qui prouve, et de répondre à cette question simple que je dirais que les deux se sont faites très lent par poser la question.
Et ainsi de passer encore plus de temps sur elle ...
", tandis que (2)" est ridicule, car,
"while (1)", et "while (true)" sont historiquement utilisé pour faire une boucle infinie qui s'attend à "casser" d'être appelé à un certain stade, à l'intérieur de la boucle basée sur une condition qui va certainement se produire.
Le "1" est simplement là pour toujours avoir la valeur true et donc, de dire que "tout (2)" est à peu près aussi idiot que de dire "while (1 + 1 == 2)", ce qui permettra également d'évaluer la valeur true.
Et si vous voulez être complètement stupide suffit d'utiliser: -
Id aiment à penser que votre codeur fait une faute de frappe qui n'a pas d'effet sur le fonctionnement du code, mais si il l'a volontairement utilisé le "2", juste pour être bizarre, puis le sac avant qu'il mette bizarre sh!t au moyen de votre code, ce qui rend difficile à lire et à travailler avec.
==
par!=
dans votre état pour le rendretrue
Qui dépend du compilateur.
Si il permet d'optimiser le code, ou si on les évalue 1 et 2 de la vraie avec le même nombre d'instructions pour un particulier, l'instruction, la vitesse d'exécution sera le même.
Dans des cas réels, il sera toujours aussi rapide, mais il serait possible d'imaginer un particulier compilateur et d'un système particulier, si cela peut être évaluée différemment.
Je veux dire: ce n'est pas vraiment un langage (C) liés à la question.
Puisque les gens qui cherchent à répondre à cette question, veulent le plus rapide de la boucle, j'aurais répondu que les deux sont également de la compilation dans le même assembly code, comme indiqué dans les autres réponses. Néanmoins, vous pouvez suggérer à l'interviewer à l'aide de 'déroulement de la boucle'; un do {} while au lieu de la boucle while.
Prudent: vous devez Vous assurer que la boucle serait au moins toujours exécuter une fois.
La boucle doit avoir une condition d'arrêt à l'intérieur.
Aussi pour ce genre de boucle, je serais personnellement préfèrent l'utilisation d'un do {} while(42) depuis tout entier, à l'exception de 0, pour faire le travail.
La réponse est évidente: comme il est posté, les deux fragments irait tout aussi remplie de boucle infinie, ce qui rend le programme infiniment lent.
Bien que la redéfinition de mots-clés de C en tant que macros serait techniquement avoir un comportement indéfini, c'est la seule façon que je peux penser à faire fragment de code rapide à tous: vous pouvez ajouter cette ligne au-dessus de la 2 fragments:
il va en effet faire
while(1)
deux fois plus vite (ou de la moitié plus lent) quewhile(2)
.La seule raison pour laquelle je peux penser à pourquoi la
while(2)
serait plus lente:Le code optimise la boucle de
cmp eax, 2
Lors de la soustraction se produit, vous êtes essentiellement en soustrayant
un.
00000000 - 00000010 cmp eax, 2
au lieu de
b.
00000000 - 00000001 cmp eax, 1
cmp
définit uniquement des drapeaux et ne fixe pas de résultat. Donc, sur les bits de poids faible-nous savoir si nous avons besoin de l'emprunter ou pas avec b. Alors qu'avec un vous devez effectuer deux soustractions avant d'obtenir un emprunt.