Тот факт, что беззнаковый объект не может быть меньше нуля, влияет на способы написания циклов. Например, в упражнениях раздела 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.

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

Выражения, в которых смешаны знаковые и беззнаковые типы, могут приводить к удивительным результатам, когда знаковое значение оказывается негативным. Важно не забывать, что знаковые значения автоматически преобразовываются в беззнаковые. Например, в таком выражении, как a * b, если а содержит значение -1, a b значение 1 и обе переменные имеют тип int, ожидается результат -1. Но если переменная а имеет тип int, а переменная b — тип unsigned, то значение этого выражения будет зависеть от количества битов, занимаемых типом int на данной машине. На нашей машине результатом этого выражения оказалось 4294967295.

Упражнения раздела 2.1.2

Упражнение 2.3. Каков будет вывод следующего кода?

unsigned u = 10, u2 = 42;

std::cout << u2 - u << std::endl;

std::cout << u - u2 << std::endl;

int i = 10, i2 = 42;

std::cout << i2 - i << std::endl;

std::cout << i - i2 << std::endl;

std::cout << i - u << std::endl;

std::cout << u - i << std::endl;

Упражнение 2.4. Напишите программу для проверки правильности ответов. При неправильных ответах изучите этот раздел еще раз.

<p>2.1.3. Литералы</p>

Такое значение, как 42, в коде программы называется литералом (literal), поскольку его значение самоочевидно. У каждого литерала есть тип, определяемый его формой и значением.

Целочисленные литералы и литералы с плавающей запятой

Целочисленный литерал может быть в десятичной, восьмеричной или шестнадцатеричной форме. Целочисленные литералы, начинающиеся с нуля (0), интерпретируются как восьмеричные, а начинающиеся с 0x или 0X — как шестнадцатеричные. Например, значение 20 можно записать любым из трех следующих способов.

Перейти на страницу:

Похожие книги