Question

Ou est-ce tout au sujet de la sémantique?

Était-ce utile?

La solution

Réponse courte:. Non, ils sont exactement les mêmes

Je suppose qu'il pourrait en théorie dépendre du compilateur; un vraiment cassé peut faire quelque chose un peu différent, mais je serais surpris.

Juste pour le plaisir, voici deux variantes qui compilent jusqu'à exactement le même code assembleur pour moi d'utiliser la version gcc x86 4.3.3 livré avec Ubuntu. Vous pouvez vérifier l'assemblage produit sur le binaire final avec objdump sur linux.

int main()
{
#if 1
    int i = 10;
    do { printf("%d\n", i); } while(--i);
#else
    int i = 10;
    for (; i; --i) printf("%d\n", i);
#endif
}

EDIT: Voici un "oranges avec des oranges" tandis que l'exemple de boucle qui compile également vers le bas à la même chose:

    while(i) { printf("%d\n", i); --i; }

Autres conseils

Si votre et en boucles font les mêmes choses, le code machine généré par le compilateur doit être (presque) le même.

Par exemple, dans il y a quelques tests, je l'ai fait quelques années,

for (int i = 0; i < 10; i++)
{
...
}

et

int i = 0;
do
{
  ...
  i++;
}
while (i < 10);

générerait exactement le même code, ou (et Neil a fait remarquer dans les commentaires) avec un JMP supplémentaire, ce qui ne fera pas une différence assez grande dans la performance à se soucier.

Il n'y a pas de différence sémantique, il n'a pas besoin d'avoir de différence établie. Mais cela dépend du compilateur. J'ai donc essayé avec avec g ++ 4.3.2, CC 5.5 et xlc6.

g ++, CC sont identiques, xlc ETAIT PAS

La différence de xlc était dans l'entrée de boucle initiale.

extern int doit( int );
void loop1( ) {
  for ( int ii = 0; ii < 10; ii++ ) {
    doit( ii );
  }
}

void loop2() {
  int ii = 0; 
  while ( ii < 10 ) {
    doit( ii );
    ii++;
  }
}

SORTIE XLC

.loop2:                                 # 0x00000000 (H.10.NO_SYMBOL)
    mfspr   r0,LR
    stu     SP,-80(SP)
    st      r0,88(SP)
    cal     r3,0(r0)
    st      r3,64(SP)
    l       r3,64(SP)  ### DIFFERENCE ###
    cmpi    0,r3,10
    bc      BO_IF_NOT,CR0_LT,__L40
...
enter code here
.loop1:                                 # 0x0000006c (H.10.NO_SYMBOL+0x6c)
    mfspr   r0,LR
    stu     SP,-80(SP)
    st      r0,88(SP)
    cal     r3,0(r0)
    cmpi    0,r3,10    ### DIFFERENCE ###
    st      r3,64(SP)
    bc      BO_IF_NOT,CR0_LT,__La8
...

Le champ d'application de la variable dans le test de la boucle while est plus large que la portée des variables déclarées dans l'en-tête de la boucle for.

Par conséquent, s'il y a des implications sur les performances comme un effet secondaire de maintenir une variable en vie plus longtemps, alors il y aura des conséquences sur les performances dans le choix entre un certain temps et une boucle (et non enveloppant le tout dans {} pour réduire la la portée de ses variables).

Un exemple pourrait être une collection concurrente qui compte le nombre de itérateurs s'y référant, et s'il existe plusieurs iterator, il applique de verrouillage pour éviter une modification concurrente, mais comme une optimisation Elide le verrouillage si un seul itérateur y fait référence . Si vous aviez alors deux boucles en fonction <=> en utilisant itérateurs différemment nommées dans le même conteneur, le chemin rapide serait prise, mais avec deux boucles le chemin <=> lent serait prise. De même, il peut y avoir des conséquences sur les performances si les objets sont grandes (plus de trafic de cache), ou utiliser des ressources système. Mais je ne peux pas penser à un exemple réel que j'ai jamais vu où il ferait une différence.

Compilateurs qui permettent d'optimiser l'aide de déroulage de boucle sera probablement le faire dans la boucle for cas.

Les deux sont équivalents. Il est une question de sémantique.

La seule différence réside peut-être dans le faire ... tout en construction, où vous reporter l'évaluation de la condition jusqu'à ce que après le corps, et peut ainsi économiser 1 évaluation.

i = 1; do { ... i--; } while( i > 0 ); 

au lieu de

for(  i = 1; i > 0; --i )
{ ....
}  

Je vous écris compilateurs. Nous compilons tous les flux de contrôle "structuré" (if, while, for, switch, do ... goto) dans les branches conditionnelles et inconditionnelles. Ensuite, nous analysons le graphe de contrôle de flux. Depuis un compilateur C doit traiter avec le général de toute façon <=>, il est plus facile de réduire tout à la branche et instructions conditionnelles-branche, alors assurez-vous de traiter ce cas bien. (Un compilateur C doit faire un bon travail non seulement sur le code écrit à la main, mais aussi sur le code généré automatiquement, ce qui peut avoir de nombreuses déclarations <=>.)

Non. S'ils font des choses équivalentes, ils compilent au même code - comme vous le dites, il est question de sémantique. Choisissez celui qui représente le mieux ce que vous essayez d'exprimer.

Idéalement, il devrait être le même, mais finalement cela dépend de votre compilateur / interpréteur. Pour être sûr, vous devez mesurer ou examiner le code assembleur généré.

La preuve qu'il peut y avoir une différence. Ces lignes produisent code assembleur différent en utilisant CC65

for (; i < 1000; ++i);   
while (i < 1000) ++i;

Sur Atmel ATMega while () est plus rapide que pour (). Pourquoi cela est expliqué dans AVR035. Le codage C efficace pour AVR

P.S. plate-forme originale n'a pas été mentionnée en question.

Continuer se comporte différemment dans et en : pour , il modifie le compteur, en , il le fait habituellement pas

Pour ajouter une autre réponse:. Dans mon expérience, le logiciel optimisation est comme une grande barbe touffue être rasés homme

  • D'abord, vous lop hors tension en gros morceaux avec des ciseaux (élaguer membres entiers de l'arbre d'appel).
  • Ensuite, vous faire court avec une tondeuse électrique (algorithmes tweak).
  • Enfin, vous raser avec un rasoir pour se débarrasser du dernier peu (optimisation de bas niveau).

Le dernier est où la différence entre et for() pourrait while(), mais probablement pas faire une différence.

P.S. Les programmeurs que je connais (qui sont tous très bons, et je soupçonne que sont un échantillon représentatif) vont essentiellement à elle dans l'autre sens.

Ils sont les mêmes que mesure du rendement va. Je tendance à utiliser while lors de l'attente pour un changement d'état (tels que l'attente d'une mémoire tampon à remplir) et for lors du traitement d'un certain nombre d'objets discrets (par exemple en passant par chaque élément d'une collection).

Il y a une différence dans certains cas.

Si vous êtes au point où cette différence importe, soit vous devez choisir un meilleur algorithme ou commencer à coder en langage assembleur. Croyez-moi, le codage dans l'assemblage est préférable de fixer votre version du compilateur.

est plus rapide while() / plus lent que for()? Revoyons quelques petites choses sur l'optimisation:

  • compilateur écrivains travaillent très dur pour se raser cycles en ayant moins d'appels à sauter, comparer, incrément, et les autres types d'instructions qu'ils génèrent.

  • instructions d'appel, d'autre part, consomment beaucoup de grandeurs plus de cycles, mais le compilateur est presque impuissant à faire quoi que ce soit pour éliminer ceux-ci.

  • Comme les programmeurs, nous écrivons beaucoup d'appels de fonction, certains parce que nous entendons, certains parce que nous sommes paresseux, et quelques-uns parce que le compilateur les glisse sans être évidente.

  • La plupart du temps, il n'a pas d'importance, parce que le matériel est si rapide, et nos emplois sont si petits, que l'ordinateur est comme un chien beagle qui Wolfes sa nourriture et en redemande.

  • Parfois, cependant, le travail est assez grand pour que la performance est un problème.

  • Que faisons-nous alors? Où est le plus grand gain?

    • Obtenir le compilateur de se raser quelques cycles de boucles et tels?
    • Trouver les appels de fonctions qui ne sont pas -really - doivent être faites tant
  • Le compilateur ne peut pas faire ce dernier. Seuls nous les programmeurs peuvent.

  • Nous devons apprendre ou enseigner comment faire cela. Il ne vient pas naturellement. Nous sommes congénitalement enclins à faire des mauvaises suppositions et parier sur eux. Obtenir de meilleurs algorithmes est un début, mais seulement un début. Nos enseignants ont besoin d'enseigner cela, si en effet ils savoir comment.

  • Profilers sont un début. Je le fais.

La citation apocryphe de Willie Sutton quand on lui demande Pourquoi avez-vous voler des banques :
Parce que est où l'argent est.

Si vous souhaitez enregistrer les cycles, savoir où ils sont.

Probablement que le style de codage.

  • car si vous connaissez le nombre d'itérations.
  • alors que si vous ne connaissez pas le nombre d'itérations.
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top