57 votes

Pourquoi une expression au lieu d'une constante, dans la conditionnelle d'un for-loop en C ?

Dans de nombreux concours de programmation, j'ai vu des personnes écrire ce type de for -boucle

for(i = 0; i < (1 << 7); i++)

Sauf erreur de ma part, c'est la même chose que

for(i = 0; i < 128; i++)

Pourquoi utiliser le (1 << 7) version ?
Le calcul de la condition à chaque fois n'est-il pas une surcharge inutile ?

76voto

ouah Points 75311

Oui, ils ont un comportement équivalent.

Alors pourquoi les gens utilisent-ils la version (1 << 7) ?

Je suppose qu'ils l'utilisent pour prouver que c'est une puissance de 2.

Calculer la condition à chaque fois doit être une charge supplémentaire ! Je ne parviens pas à trouver la raison de cette situation !

Pas vraiment, tout compilateur normal remplacera 1 << 7 par 128 et donc les deux boucles auront les mêmes performances.

(C11, 6.6p2) "Une expression constante peut être évaluée pendant la traduction plutôt que pendant l'exécution, et par conséquent peut être utilisée à n'importe quel endroit où une constante peut se trouver."

31voto

barak manos Points 10969

Traduisons chacune de ces options en langage clair :

for(i = 0; i < (1 << 7); i++) // For every possible combination of 7 bits
for(i = 0; i < 128; i++)      // For every number between 0 and 127

Le comportement à l'exécution doit être identique dans les deux cas.

En fait, en supposant un compilateur décent, même le code d'assemblage devrait être identique.

La première option est donc essentiellement utilisée dans le seul but de "faire une déclaration".

Vous pouvez tout aussi bien utiliser la deuxième option et ajouter un commentaire ci-dessus.

19voto

Yu Hao Points 40603

1 << 7 est une expression constante, le compilateur la traite comme 128 il n'y a pas de surcharge dans le temps d'exécution.

Sans le corps de la boucle, il est difficile de dire pourquoi l'auteur l'utilise. Il est possible qu'il s'agisse d'une boucle qui itère sur un élément associé à 7 bits, mais ce n'est qu'une supposition.

14voto

Shafik Yaghmour Points 42198

Alors pourquoi les gens utilisent-ils la version (1 << 7) ?

Il s'agit d'une forme de documentation, ce n'est pas un chiffre magique mais 2^7 ( deux à la septième puissance ) qui est significatif pour celui qui a écrit le code. Un compilateur optimisant moderne devrait générer exactement le même code pour les deux exemples. Il n'y a donc aucun coût à utiliser cette forme et l'avantage est d'ajouter un contexte.

Utilisation de godbolt nous pouvons vérifier que c'est effectivement le cas, au moins pour plusieurs versions de gcc , clang et icc . En utilisant un exemple simple avec des effets secondaires pour s'assurer que le code n'est pas totalement optimisé :

#include <stdio.h>

void forLoopShift()
{
  for(int i = 0; i < (1 << 7); i++)
  {
    printf("%d ", i ) ;
  }
}

void forLoopNoShift()
{
  for(int i = 0; i < 128; i++)
  {
        printf("%d ", i ) ;
  }
}

Pour la partie pertinente du code, nous pouvons voir qu'ils génèrent tous les deux ce qui suit voir en direct :

cmpl    $128, %ebx

Ce que nous avons, c'est un expression constante entière tel que défini dans la section du projet de norme C11 6.6 Expressions constantes qui dit :

Une constante entière expression117) doit être de type entier et ne doit avoir que des opérandes qui sont des constantes entières, des constantes d'énumération, des constantes de caractères, des expressions sizeof des expressions dont les résultats sont des constantes entières, [...]

et :

Les expressions constantes ne doivent pas contenir d'opérateurs d'affectation, d'incrémentation, de décrémentation, d'appel de fonction, ou des opérateurs de virgule, sauf lorsqu'ils sont contenus dans une sous-expression qui n'est pas évaluée.115)

et nous pouvons voir qu'une expression constante est autorisée à être évaluée pendant la traduction :

Une expression constante peut être évaluée pendant la traduction plutôt que pendant l'exécution, et peut donc être utilisée à n'importe quel endroit où une constante peut se trouver.

5voto

unohu Points 404

for(i = 0 ; i < (1 << 7) ; i++)

et

pour(i = 0 ; i < 128 ; i++)

donne les mêmes performances mais le développeur peut tirer un avantage énorme dans le cas où for(i = 0 ; i < (1 << 7)) ; i++) est utilisé dans une boucle comme

for(int k = 0; k < 8; k++)
{
  for(int i = 0; i < (1 << k); i++)
   {
    //your code
    }

}

Maintenant, il est dans la limite supérieure de la boucle interne, c'est-à-dire que (1 << k) change avec une puissance de 2 temps d'exécution. Mais c'est applicable si votre algorithme nécessite cette logique.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X