Itération sur tous les entiers non signés dans une boucle for

Disons que je veux parcourir tous les entiers d’une boucle for . Par souci de discussion, supposons que j’appelle une fonction inconnue f(unsigned x) pour chaque entier:

 for (unsigned i = 0; i < UINT_MAX; i++) { f(i); } 

Bien entendu, ce qui précède ne parvient pas à parcourir tous les entiers, car il en manque un: UINT_MAX. Changer la condition pour i <= UINT_MAX ne donne qu’une boucle infinie, car c’est une tautologie.

Vous pouvez le faire avec une boucle do-while while, mais vous perdez toutes les subtilités de la syntaxe for .

Puis-je avoir mon gâteau ( for boucles) et le manger aussi (itérer sur tous les entiers)?

Vous pouvez le faire avec une boucle do-while, mais vous perdez toutes les subtilités de la syntaxe for.

Il est toujours possible de faire une boucle do-while en utilisant une scope de bloc anonyme:

 { unsigned i = 0; do { f(i); } while (++i != 0); } 

Bien que cette construction ne soit peut-être pas très idiomatique, elle constitue un candidat évident pour un code d’assemblage clair. Par exemple, gcc -O comstack comme gcc -O :

 .L2: mov edi, ebx ; ebx starts with zero call f add rbx, 1 cmp rbx, rbp ; rbp is set with 4294967296 jne .L2 

Vous devrez effectuer le test à la fin du corps de la boucle, à la manière d’un do-while:

 for (unsigned int i = 0; /* nothing */; i++) { ... if (i == UINT_MAX) { break; } } 

Pour qu’un test dans la position standard de test de boucle fonctionne, vous devez suivre l’itération en cours de manière à pouvoir distinguer les états UINT_MAX + 2: un pour chaque fois que vous entrez dans le corps de la boucle et un pour l’un ne pas Un unique unsigned int ne peut pas gérer cela, vous aurez donc besoin d’au moins une variable auxiliaire ou d’un compteur de boucles plus grand.

Vous pouvez utiliser une autre variable pour détecter le moment où vous avez effectué une boucle.

 for (unsigned int i = 0, repeat = 0; !(i == 0 && repeat); i++, repeat = 1) { ... } 

La méthode classique pour implémenter efficacement votre itération, avec un seul test, est une boucle do / while While:

 unsigned i = 0; do { f(i); } while (i++ != UINT_MAX); 

Si vous insistez pour utiliser une boucle for :

 for (unsigned i = 0;; i++) { f(i); if (i == UINT_MAX) break; } 

Voici une autre variante avec 2 variables où toute la logique est à l’intérieur des expressions for :

 for (unsigned int i = 0, not_done = 1; not_done; not_done = (i++ - UINT_MAX)) { f(i); } 

Cela pourrait produire du code plus lent en raison de la variable supplémentaire, mais comme l’a commenté clang , clang et icc comstacknt en un code très efficace .

Une solution facile serait,

 unsigned i; for (i=0; i 

Utilisez un type entier plus grand:

 #include  #include  int main() { for (unsigned long i = 0; i <= UINT_MAX; i++) { f(i); } } 

Cette version utilise stdint pour plus de cohérence

 #include  #include  int main() { for (uint_fast64_t i = 0; i <= UINT32_MAX; ++i) { f(i); } }