Каков наилучший способ сделать обратный цикл for с беззнаковым индексом? - PullRequest
56 голосов
/ 20 марта 2009

Моя первая попытка реверс для цикла , который делает что-то n раз, была что-то вроде:

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

Это завершается с ошибкой , потому что в арифметика без знака i гарантированно всегда будет больше или равна нулю, следовательно, условие цикла всегда будет выполняться К счастью, компилятор gcc предупредил меня о «бессмысленном сравнении», прежде чем мне стало интересно, почему цикл выполняется бесконечно.


Я ищу элегантный способ решения этой проблемы, учитывая, что:

  1. Это должен быть цикл в обратном направлении.
  2. Индекс цикла должен быть без знака.
  3. n является беззнаковой константой.
  4. Он не должен основываться на «неясной» кольцевой арифметике целых чисел без знака.

Есть идеи? Спасибо:)

Ответы [ 20 ]

94 голосов
/ 20 марта 2009

Как насчет:

for (unsigned i = n ; i-- > 0 ; )
{
  // do stuff with i
}
12 голосов
/ 20 марта 2009
for ( unsigned int loopIndex = n; loopIndex > 0; --loopIndex ) {
    unsigned int i = loopIndex - 1;
    ...
} 

или

for ( unsigned int loopIndex = 0; loopIndex < n; ++loopIndex ) {
    unsigned int i = n - loopIndex - 1;
    ...
} 
11 голосов
/ 20 марта 2009
for ( unsigned int i = n; i != 0; i-- ) {
    // do something with i - 1
    ...     
}

Обратите внимание, что если вы используете C ++ и C, использование! = Является хорошей привычкой, когда вы переходите на использование итераторов, где <= и т. Д. Могут быть недоступны. </p>

9 голосов
/ 11 мая 2011

Почему бы просто:

unsigned int i = n;
while(i--)
{ 
    // use i
}

Это соответствует всем требованиям, перечисленным в основной части вопроса. Он не использует ничего, что может провалить проверку кода или нарушить стандарт кодирования. Единственное возражение, которое я мог видеть, это то, что ОП действительно настаивал на цикле for, а не на простом способе генерации i = (n-1) .. 0.

8 голосов
/ 20 марта 2009

Я бы хотел использовать

 for ( unsigned int i = n; i > 0; )  {
    --i;
    ...     
 }

это почти то же самое, что и ответ скиза, (он пропускает последнее ненужное уменьшение, но компилятор должен его оптимизировать) и фактически пропустит проверку кода. В каждом стандарте кодирования, с которым мне приходилось работать, не было мутаций в условном правиле.

8 голосов
/ 20 марта 2009
for ( unsigned int i = n; i > 0; i-- ) {
    ...  
    i-1 //wherever you've been using i   
}
5 голосов
/ 20 марта 2009

Может быть, так? ИМХО это понятно и понятно. Вы можете опустить if (n> = 1), если он как-то неявно известен.

if(n>=1) {
    // Start the loop at last index
    unsigned int i = n-1;
    do {
       // a plus: you can use i, not i-1 here
    } while( i-- != 0 );
}

Другая версия:

if(n>=1) {
    unsigned int i = n;
    do {
       i--;

    } while( i != 0 );
}

Первый код без оператора if будет выглядеть так:

unsigned int i = n-1;
do {

} while( i-- != 0 );
4 голосов
/ 20 марта 2009

Или вы можете положиться на поведение обтекания unsigned int, если вам нужно индексирование от n-1 до 0

for(unsigned int i = n-1; i < n; i--) {
    ...
}
4 голосов
/ 20 марта 2009
for (unsigned int i = n-1; i<(unsigned int)-1; i--)

ОК, его "неясная кольцевая арифметика".

3 голосов
/ 20 марта 2009

Единственная причина, по которой я упоминаю эту опцию, заключается в том, что я не увидел ее в списке.

for ( unsigned int i = n-1; i < n; i-- ) {
... 
}

Абсолютно против интуиции, но это работает. причина, по которой это работает, состоит в том, что вычитание 1 из 0 дает наибольшее число, которое может быть представлено целым числом без знака.

В общем, я не думаю, что будет хорошей идеей работать с целыми числами без знака и с выражениями, особенно при вычитании.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...