Подтвердить что ты не робот

Unsigned int обратная итерация с петлями

Я хочу, чтобы переменная итератора в цикле for обратного итерации равнялась 0 как unsigned int, и я не могу представить аналогичное сравнение с i > -1, как это было бы, если бы это был signed int.

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

Но это кажется очень неясным, поскольку он полагается на числовое переполнение целого числа без знака, которое должно быть выше 10.

Может быть, у меня просто нет четкой головы, но лучше ли это сделать...

Отказ от ответственности: это простой пример использования, верхний предел 10 тривиален, он может быть любым, а i должен быть unsigned int.

4b9b3361

Ответ 1

Вы можете использовать

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

Итерирует от n-1 до 0.

Ответ 2

Следующее делает то, что вы хотите:

for (unsigned i = 10; i != static_cast<unsigned>(-1); --i)
{
    // ...
}

Это отлично определено и фактически работает. Арифметика на подписанных типах точно определяется стандартом. Действительно:

От 4.7/2 (относительно приведения к неподписанному типу):

Если тип назначения не указан, результирующее значение представляет собой наименьшее беззнаковое целое, совпадающее с исходным целым (по модулю 2 ^ n, где n - количество бит, используемых для представления неподписанного типа)

и 3.9.1/4

Беззнаковые целые числа, объявленные без знака, должны подчиняться законам арифметики по модулю 2 ^ n, где n - количество бит в представлении значений этого конкретного размера целого числа

Ответ 3

Мой шаблон для этого обычно...

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

Ответ 4

Действительно ли вы выполняете итерацию с какого-то числа больше std::numeric_limits<int>::max()? Если нет, я бы предложил просто использовать обычный int в качестве переменной цикла и static_cast для unsigned в местах вашего кода, которые ожидают, что он будет неподписанным. Таким образом, вы можете использовать интуитивное условие >= 0 или > -1, и в целом я ожидаю, что он будет более читабельным, чем любая из неподписанных альтернатив.

static_cast просто должен сказать компилятору, как работать с переменной и вообще не иметь никаких последствий для производительности.

Ответ 5

Я бы использовал две переменные:

unsigned int start = 10;
for (unsigned int j = 0, i = start; j <= start; ++ j, -- i) {
    // ...
}

Вы также можете использовать цикл while:

unsigned int start = 10;
unsigned int i = start + 1;
while (i --) {
    // ...
}

Ответ 6

for(unsigned i = x ; i != 0 ; i--){ ...

И если вы хотите выполнить тело цикла при я == 0 и остановитесь после этого. Просто начните с i = x+1;

Кстати, почему я должен быть без знака?

Ответ 7

Я могу думать, что эти два варианта - это либо литые, либо поющие числа (может быть сделано неявно, например, сравнение с -1) или использовать условие цикла для проверки переполнения следующим образом:

for(unsigned i=10;i>i-1;--i){ } // i = 10, 9, ... , 1
for(unsigned i=10;i+1>i;--i){ } // i = 10, 9, ... , 1,0

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

Ответ 8

Просто:

int start = 10;
for(unsigned int iPlus1 = start + 1 ; iPlus1 > 0 ; iPlus1--) {
  // use iPlus1 - 1 if you need (say) an array index
  a[iPlus1 - 1] = 123; // ...
}

Нет

Ответ 9

Вы можете попробовать и определить следующий макрос:

#define for_range(_type, _param, _A1, _B1) \
    for (_type _param = _A1, _finish = _B1,\
    _step = static_cast<_type>(2*(((int)_finish)>(int)_param)-1),\
    _stop = static_cast<_type>(((int)_finish)+(int)_step); _param != _stop; \
_param = static_cast<_type>(((int)_param)+(int)_step))

Теперь вы можете использовать его:

for_range (unsigned, i, 10,0)
{
    cout << "backwards i: " << i << endl;
}

Он может использоваться для итерации назад и вперед через unsigned, целые числа, перечисления и символы:

for_range (char, c, 'z','a')
{
    cout << c << endl;
}

enum Count { zero, one, two, three }; 

for_range (Count, c, zero, three)
{
    cout << "forward: " << c << endl;
}

Несмотря на свое неудобное определение, он оптимизирован очень хорошо. Я посмотрел на дизассемблер в VС++. Код чрезвычайно эффективен. Не откладывайте, а три для операторов: компилятор будет производить только один цикл после оптимизации! Вы даже можете определить замкнутые контуры:

unsigned p[4][5];

for_range (Count, i, zero,three)
    for_range(unsigned int, j, 4, 0)
    {   
        p[i][j] = static_cast<unsigned>(i)+j;
    }

Вы, очевидно, не можете перебирать нумерованные типы с пробелами.

Ответ 10

Еще один способ:

for(unsigned i = n-1; i < n ; --i) 
{       
    // Iterates from n-1 to 0
}

Simillarly для size_t (беззнаковый целочисленный тип) использует тот же трюк

for(std::size_t i = n-1; i < n ; --i) 
{       
    // Iterates from n-1 to 0
}