2013-07-25 4 views
1

Ниже приведены два цикла. Первый работает хорошо, а второй - бесконечный цикл. Зачем?unsigned int вызывает бесконечный цикл for

for (unsigned int i=0; i<3; ++i) 
{ 
    std::cout << "i= " << i << std::endl; // this gives proper result 
} 

for (unsigned int i=3; i>=0; --i) 
{ 
    std::cout << "i= " << i << std::endl; // infinite loop 
} 

ответ

12

unsigned int никогда не может быть меньше 0. Это то, что делает его беззнаковое. Если вы включите некоторые предупреждающие флаги, ваш компилятор должен рассказать вам о вашей проблеме: i >= 0 is всегда верно для значения unsigned.

не

Clang, например, требуется никаких специальных флагов на всех предупредить:

example.cpp:5:29: warning: comparison of unsigned expression >= 0 is always true 
     [-Wtautological-compare] 
    for (unsigned int i=3; i>=0; --i) 
          ~^ ~ 
1 warning generated. 

GCC требуется -Wextra:

example.cpp: In function ‘int main()’: 
example.cpp:5: warning: comparison of unsigned expression >= 0 is always true 
3

unsigned int не может быть меньше нуля (что цикл своего состояния является проверка). Когда i во втором цикле уменьшается с 0, он обходит вокруг UINT_MAX, и цикл продолжается.

2

Минимальное значение для unsigned int i равно 0; все остальное было бы отрицательным и требовало бы знакового бита, который определенно не имеет значения unsigned.

Так что i >= 0 всегда будет оцениваться как истинный.

3

Другие ответы (до сих пор) являются правильными; поскольку i не имеет знака, i >= 0 всегда истинно, и поэтому у вас есть бесконечный цикл.

Но это не говорит вам, как это исправить. Если вы хотите итерировать диапазон без знака от, скажем, от 3 до 0, кажется, нет простого способа сделать это. Кроме изменения типа i или направление диапазона (и может быть причин, вы не можете сделать это), вы можете сделать это:

for (unsigned int i=3; ; --i) 
{ 
    std::cout << "i= " << i << std::endl; 
    if (i == 0) break; 
} 

Это не так чист, как простой for петли с не break, но он выполняет эту работу.

+0

Обычно я ненавижу появляться таким образом, но вы можете проверить мой ответ о том, как избавиться от этого досадного 'break'. ;) – syam

+0

@syam: Пожалуйста, ворваться! Я считаю, что моя версия более читаема, но другие могут отличаться. –

+0

Ну, я согласен с чистой читабельностью, но мой - хорошо известный шаблон, поэтому читаемость - это не проблема, как только вы это знаете, и это немного легче написать. Просто подумал, что я уведомит вас, если вы еще этого не знаете, подумал, что это может вас заинтересовать. :) – syam

3

В дополнение к ответу Кит Томпсон, есть другой способ, чтобы написать его, что не требует break внутри цикла:

for (unsigned int i = 3; i--;) { 
    std::cout << "i= " << i << std::endl; 
} 

Обратите внимание, как i-- действует как условие завершения и как afterthough, все в одном. Использование оператора постфиксального декремента важно, потому что оно гарантирует, что вы фактически выполняете цикл 3 раза, начиная с 2 на первой итерации и заканчивая на 0, включая.

+0

Почему это работает? Это здорово, но это всегда будет работать? – JeffCharter

0

В вашей второй петле условие остановки цикла заключается в том, что i должно быть меньше 0. Диапазон unsigned int равен 0 to 65535. поэтому здесь unsigned int i не может быть меньше нуля. Итак, ваше условие всегда верно, в результате цикл становится бесконечным. Использование signed int может решить проблему.

Смежные вопросы