> // выводит 4294967264
Во втором выражении, прежде чем будет осуществлено сложение, значение >-42
типа >int
преобразуется в значение типа unsigned. Преобразование отрицательного числа в тип >unsigned
происходит точно так же, как и при попытке присвоить это отрицательное значение объекту типа >unsigned
. Произойдет "обращение значения" (wrap around), как было описано выше.
При вычитании значения из беззнакового объекта, независимо от того, один или оба операнда являются беззнаковыми, следует быть уверенным том, что результат не окажется отрицательным:
>unsigned u1 = 42, u2 = 10;
>std::cout << u1 - u2 << std::endl; // ok: результат 32
>std::cout << u2 - u1 << std::endl; // ok: но с обращением значения
Тот факт, что беззнаковый объект не может быть меньше нуля, влияет на способы написания циклов. Например, в упражнениях раздела 1.4.1 (стр. 39) следовало написать цикл, который использовал оператор декремента для вывода чисел от >10
до >0
. Написанный вами цикл, вероятно, выглядел примерно так:
>for (int i = 10; i >= 0; --i)
> std::cout << i << std::endl;
Казалось бы, этот цикл можно переписать, используя тип >unsigned
. В конце концов, мы не планируем выводить отрицательные числа. Однако это простое изменение типа приведет к тому, что цикл никогда не закончится:
>// ОШИБКА: u никогда не сможет стать меньше 0; условие
>// навсегда останется истинным
>for (unsigned u = 10; u >= 0; --u)
> std::cout << u << std::endl;
Рассмотрим, что будет, когда >u
станет равно >0
. На этой итерации отображается значение >0
, а затем выполняется выражение цикла >for
. Это выражение, >--u
, вычитает >1
из >u
. Результат, >-1
, недопустим для беззнаковой переменной. Как и любое другое значение, не попадающее в диапазон допустимых, это будет преобразовано в беззнаковое значение. При 32-разрядном типе >int
результат выражения >--u
при u равном >0
составит >4294967295
.
Исправить этот код можно, заменив цикл >for
циклом >while
, поскольку последний осуществляет декремент прежде (а не после) отображения значения:
>unsigned u = 11; // начать цикл с элемента на один больше
> // первого, подлежащего отображению
>while (u > 0) {
> --u; // сначала декремент, чтобы последняя итерация отобразила 0
> std::cout << u << std::endl;
>}
Цикл начинается с декремента значения управляющей переменной цикла. В начале последней итерации переменная >u
будет иметь значение >1
, а после декремента мы отобразим значение >0
. При последующей проверке условия цикла >while
значением переменной >u
будет >0
, и цикл завершится. Поскольку декремент осуществляется сначала, переменную >u
следует инициализировать значением на единицу больше первого подлежащего отображению значения. Следовательно, чтобы первым отображаемым значением было >10
, переменную >u
инициализируем значением >11
.
Выражения, в которых смешаны знаковые и беззнаковые типы, могут приводить к удивительным результатам, когда знаковое значение оказывается негативным. Важно не забывать, что знаковые значения автоматически преобразовываются в беззнаковые. Например, в таком выражении, как