×
Traktatov.net » Язык программирования C++. Пятое издание » Читать онлайн
Страница 32 из 714 Настройки

>                                 // выводит 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.

Внимание! Не смешивайте знаковые и беззнаковые типы

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