12
votes

Pour la condition de boucle pour arrêter à 0 lorsque vous utilisez des entiers non signés?

J'ai une boucle qui doit aller de n à 0 (inclusivement). Mon i de la variable est de type taille_t qui est généralement non signé. J'utilise actuellement le code suivant: xxx

est-ce correct? Y a-t-il un meilleur moyen de gérer la condition?

Merci,

Vincent.


4 commentaires

Hmm c'est une très bonne question.


Taille_T est garanti d'être non signé et votre utilisation de (taille_t) -1 est correcte. Vous n'avez qu'un problème lorsque N est égal à cette valeur ...


@supercat: Comme cela se produit à l'intérieur d'une autre boucle, je préfère avoir une autre boucle pour "synchronicité".


Duplicaté possible de Qu'est-ce que c'est la meilleure façon de faire une boucle inverse "pour" avec un index non signé?


8 Réponses :


4
votes

Vous pouvez utiliser ceci:

for (size_t i = n + 1; i-- > 0;)
{
}


3 commentaires

Cela ira de n-1 à 0, pas de n à 0.


Vous avez raison, j'ai raté l'exigence «inclusivement», c'est corrigé, merci


Cela ne fonctionnerait pas dans le cas pathologique avec n étant taille_max . Bien sûr, vous ne voudriez probablement pas être itération de taille_max à 0 de toute façon ...



0
votes

Étant donné que l'integer non signé va rouler dans sa valeur max lors de la décrémentation de zéro, vous pouvez essayer ce qui suit, à condition que n code> est inférieur à cette valeur maximale (quelqu'un s'il vous plaît corriger-moi si c'est UB ):

for ( size_t i = N; i <= N; i-- ) { /* ... */ }


2 commentaires

Cela réduira probablement la valeur de N sur chaque itération, ce qui fait mal sans douleur.


Où as-tu eu cette idée folle? Comment est-ce différent de pour (i = 0; i ?



3
votes
for ( size_t i = N + 1 ; i-- > 0 ; ) { ... }

1 commentaires

N'utilisez pas i <= n comme condition. Il va probablement perdre du temps à recharger n de la mémoire sur chaque itération, et si n se trouve être Taille_max Vous avez une boucle infinie.



1
votes

Vous pouvez utiliser une deuxième variable comme compteur de boucle pour que la plage d'itération soit claire sur un réviseur futur. xxx


0 commentaires

7
votes

Oui, c'est correct et c'est une approche très courante. Je ne voudrais pas envisager de le changer.

Arithmétique sur les types d'entiers non signés est garanti d'utiliser modulo 2 ^ n arithmétique (où n est le nombre de bits de valeur dans le type) et le comportement sur le trop-plein est bien défini. Le résultat est converti dans la plage 0 sur 2 ^ n - 1 en ajoutant ou en soustrayant des multiples de 2 ^ n (c'est-à-dire modulo 2 ^ n arithmétique).

-1 converti en un type d'entier non signé (dont taille_t est un) convertit sur 2 ^ n - 1 . - utilise également modulo 2 ^ n arithmétique pour types non signés afin un type non signé avec la valeur 0 sera décrémenté à 2 ^ n - 1 . Votre état de terminaison de boucle est correct.


0 commentaires

5
votes

Personnellement, j'utiliserais simplement une construction de boucle différente, mais à chacun leur propre: xxx

(vous pouvez simplement utiliser (i -) comme le Condition en boucle, mais on ne devrait jamais transmettre une chance d'utiliser le -> "opérateur").


1 commentaires

+1 pour utiliser l'opérateur -> . C code est destiné à être obscurci et c'est amusant :)



5
votes

juste parce que pour code> a un endroit pratique pour mettre un test au début de chaque itération ne signifie pas que vous devez l'utiliser. Pour gérer N à 0 inclusif em>, le test doit être à la fin, au moins si vous vous souciez de gérer la valeur maximale. Ne laissez pas la commodité vous sucer à mettre le test au mauvais endroit.

for (size_t i = N;; --i) {
    ...
    if (i == 0) break;
}


0 commentaires

1
votes
for (i=N; i+1; i--)

1 commentaires

Notez que, comme toute solution, à l'exception des boucles de fonctionnement / tandis que des boucles et de l'équivalent pour / rompez la construction, cela échouera si n est taille_max .