3.1.2. Выход за пределы диапазона при присваивании
3.1.2. Выход за пределы диапазона при присваивании
Начнем с рассмотрения простого примера (листинг 3.1. проект Assignment1 на компакт-диске).
Листинг 3.1. Неявное преобразование знакового числа в беззнаковое при присваивании
procedure TForm1.Button1Click(Sender: TObject);
var
X: Byte;
Y: ShortInt;
begin
Y:= -1;
X:= Y;
Label1.Caption:= IntToStr(X);
end;
При выполнении этого примера будет выведено значение 255. Здесь мы сталкиваемся с тем, что все разряды значения Y без дополнительных проверок копируются в X, но если Y интерпретируется как знаковое число, то X — как беззнаковое, а числам 255 и -1 в восьмиразрядном представлении соответствует одна и та же комбинация битов.
Примечание
Промежуточная переменная Y понадобилась потому, что прямо присвоить переменной значение, выходящее за ее диапазон, компилятор не позволит — возникнет ошибка компиляции "Constant expression violates subrange bounds".
Строго говоря, в Delphi предусмотрена защита от подобного присваивания. Если включить опцию Range checking (включается в окне Project/Options… на закладке Compiler или директивой компилятора {$R+} или {$RANGECHECKS ON}), то при попытке присвоения X:= Y возникнет исключение ERangeError. Но по умолчанию эта опция отключена (для повышения производительности — дополнительные проверки требуют процессорного времени), поэтому программа без сообщений об ошибке выполняет такое неправильное присваивание.
В следующем примере (листинг 3.2, проект Assignment2 на компакт-диске) мы рассмотрим присваивание числу такого значения, которое не укладывается ни в знаковый, ни в беззнаковый диапазон.
Листинг 3.2. Присваивание переменной значения, выходящего за рамки диапазона
procedure TForm1.Button1Click(Sender: TObject);
var
X: Byte;
Y: Word;
begin
Y:= 1618;
X:= Y;
Label1.Caption:= IntToStr(X)
end;
На экране появится число 82. Разберемся, почему это происходит. Число 1618 в двоичной записи равно 00000110 01010010. При присваивании этого значения переменной X старшие восемь битов "некуда девать", поэтому они просто игнорируются. В результате в Х записывается число 01010010, т. е. 82.
Разумеется, при включенной опции Range checking и в этом случае произойдет исключение ERangeError.
Приведенные примеры показывают два основных источника неожиданностей, возникающих при присваивании значения целой переменной:
1. При смешении знаковых и беззнаковых чисел значение меняется из-за того, что старший бит интерпретируется то как знак числа, то как старший разряд.
2. При присваивании переменной значения, требующего большего числа разрядов, "лишние" разряды просто игнорируются.
Все проблемы при присваивании сводятся к одному из этих случаев или к их комбинации.
Все эти ситуации при выключенной опции Range checking приводят к ошибкам, которые бывает очень трудно обнаружить. Из-за этого рекомендуется включать эту опцию хотя бы на этапе отладки.
В некоторых случаях возможность присваивания значений, выходящих за пределы диапазона переменной, может быть необходимой (например, для реализации "хитрых" алгоритмов или при сопряжении сторонних библиотек, одна из которых использует знаковые типы, другая — беззнаковые). Чтобы включение ERangeError не возникало, следует предусмотреть явное приведение типа. Например, следующий код работает без исключений при включенной опции Range checking (листинг 3.3).
Листинг 3.3. Явное приведение типа для подавления исключений
procedure TForm1.Button1Click(Sender: TObject);
var
X: Byte;
Y: ShortInt;
begin
Y:= -1;
X:= Byte(Y);
Label1.Caption:= IntToStr(X)
end;
В результате его выполнения переменная X получает значение 255.
Более 800 000 книг и аудиокниг! 📚
Получи 2 месяца Литрес Подписки в подарок и наслаждайся неограниченным чтением
ПОЛУЧИТЬ ПОДАРОКДанный текст является ознакомительным фрагментом.
Читайте также
За пределы POSIX: сигналы в сети
За пределы POSIX: сигналы в сети А теперь, «на закуску», посмотрим справочную информацию по системной команде kill (послать сигнал). Вы, должно быть, помните, что в QNX есть дополнительная возможность получить справку по любой команде системы, используя команду # use
Определение диапазона адресов
Определение диапазона адресов В листинге 5.1 представлена чрезвычайно простая конфигурация DHCP, в которой определяется один диапазон IP-адресов. Для указания диапазона адресов используется декларация subnet, которая имеет следующий вид:subnet 192.168.1.0 netmask 255.255.255.0 { range 192.168.1.50
Глава 10. Распространение сети за пределы вашего помещения
Глава 10. Распространение сети за пределы вашего помещения Первоначальной идеей спецификации 802.11b было обеспечение беспроводных подключений к сетям на ограниченной территории, например в офисах, домах и общественных учреждениях. Wi-Fi предполагалось сделать простым
Использование свойств Cells для определения диапазона
Использование свойств Cells для определения диапазона При использовании без координат свойство Cells объекта Worksheets указывает на диапазон, включающий все ячейки данного рабочего листа. По аналогии, свойства Cells объекта Application ( Application. Cells ) ссылаются на все ячейки листа,
Работа с отдельными ячейками диапазона
Работа с отдельными ячейками диапазона Хотя можно с помощью одного оператора назначить одно значение всем ячейкам диапазона, как показано в предыдущем примере, в Excel нет метода, позволяющего с помощью единственного действия изменять имеющиеся значения многоячеечного
6.2.2. Нахождение границ диапазона
6.2.2. Нахождение границ диапазона Методы first и last возвращают соответственно левую и правую границу диапазона. У них есть синонимы begin и end (это еще и ключевые слова, но интерпретируются как вызов метода, если явно указан вызывающий объект).r1 = 3..6r2 = 3...6r1a, r1b = r1. first, r1.last # 3,6r1c, r1d =
6.2.3. Обход диапазона
6.2.3. Обход диапазона Обычно диапазон можно обойти. Для этого класс, которому принадлежат границы диапазона, должен предоставлять осмысленный метод succ (следующий).(3..6).each {|x| puts x } # Печатаются четыре строки # (скобки обязательны).Пока все хорошо. И
7.6. Сортировка диапазона
7.6. Сортировка диапазона ПроблемаИмеется диапазон элементов, которые требуется отсортировать.РешениеДля сортировки диапазонов имеется целый набор алгоритмов. Можно выполнить обычную сортировку (в восходящем или нисходящем порядке) с помощью sort, определенного в
7.7. Разделение диапазона
7.7. Разделение диапазона ПроблемаИмеется диапазон элементов, которые требуется каким-либо образом разделить на группы. Например, необходимо переместить в начало диапазона все элементы, которые меньше определенного значения.РешениеДля перемещения элементов
11.4. Фильтрация значений, выпадающих из заданного диапазона
11.4. Фильтрация значений, выпадающих из заданного диапазона ПроблемаТребуется проигнорировать содержащиеся в последовательности значения, которые располагаются ниже или выше заданного диапазона.РешениеИспользуйте функцию remove_copy_if, определенную в <algorithm>, как
Шутка №1 — ограничение диапазона движения мыши
Шутка №1 — ограничение диапазона движения мыши Итак, первая шутка заключается в наложении ограничения на диапазон движения мыши:сurs:= Rect(0, 0, Screen.Width div 2, Screen.Height);ClipCursor(@curs);После этого указатель мыши можно будет перемещать только в одной половине
Преобразования типов при присваивании
Преобразования типов при присваивании В операциях присваивания тип значения, которое присваивается, преобразуется к типу переменной, получающей это значение. Преобразования при присваивании допускаются даже в тех случаях, когда они влекут за собой потерю
Пределы полиморфизма
Пределы полиморфизма Неограниченный полиморфизм был бы несовместим со статическим понятием типа. Допустимость полиморфных операций определяется наследственностью.Все примеры полиморфных присваиваний, такие, как p := r и p := t, в качестве типа источника используют
Кафедра Ваннаха: Проблема диапазона Михаил Ваннах
Кафедра Ваннаха: Проблема диапазона Михаил Ваннах Опубликовано 06 сентября 2012 года Несмотря на все чудеса интерактивного музея «Лунариум», да и приборы наблюдательной площадки, сердцем планетария является Большой звёздный зал. Именно там можно