Чтение онлайн

на главную

Жанры

О чём не пишут в книгах по Delphi

Григорьев Антон Борисович

Шрифт:

3.1.3. Переполнение при арифметических операциях

Переполнением принято называть ситуацию, когда при операциях над переменной результат выходит за пределы ее диапазона. Рассмотрим следующий пример (листинг 3.4, проект Overflow1 на компакт-диске).

Листинг 3.4. Переполнение при вычитании

procedure TForm1.Button1Click(Sender: TObject);

var X: Byte;

begin

 X := 0;

 X := X - 1;

 Label1.Caption := IntToStr(X)

end;

Переменная

X
получит значение 255, поскольку при вычитании получается -1, что в беззнаковом формате соответствует 255. В принципе, этот пример практически эквивалентен примеру Assignment1, за исключением того, что значение -1 появляется в результате арифметических операций.

Немного изменим этот пример — заменим оператор вычитания функцией

Dec
(листинг 3.5, пример Overflow2 на компакт-диске).

Листинг 3.5. Переполнение при декременте

{$R+}

procedure TForm1.Button1Click(Sender: TObject);

var X: Byte;

begin

 X := 0;

 Dec(X);

 Label1.Caption := IntToStr(X);

end;

Результат получается тот же (X получает значение 255), но обратите внимание: несмотря на то, что опция Range checking включена, исключение не возникает. Этим пример Overflow2 отличается от Overflow1 — там исключение возникнет. Связано это с тем, что переполнение при использовании

Dec
и подобных ей функций контролируется другой опцией — Overflow checking (в коде программы включается директивой
{$Q+}
или
{$OVERFLOWCHECKS ON}
). Эта опция по умолчанию тоже отключена и ее также рекомендуется включать при отладке. При ее включении в данном примере возникнет исключение
EIntOverflow
.

3.1.4. Сравнение знакового и беззнакового числа

Посмотрим, что произойдет, если мы попытаемся сравнить знаковое и беззнаковое число (листинг 3.6, пример Compare1 на компакт-диске).

Листинг 3.6. Сравнение "одинаковых" знакового и беззнакового числа

procedure TForm1.Button1Click(Sender: TObject);

var

 X: Byte;

 Y: ShortInt;

begin

 Y := -1;

 X := Y;

 if X = Y then Label1.Caption := 'Равно';

 else Label1.Caption := 'He равно';

end;

В окне появится надпись Не равно, хотя последовательность битов в переменных

X
и
Y
будет, как мы уже знаем, одинаковая. Надпись соответствует действительности —
X
(255) действительно не равно
Y
(-1). Разберемся, почему так происходит.

Те, кто успел самостоятельно откомпилировать пример Compare1, могли заметить предупреждение компилятора на строке со сравнением: "Comparing signed and unsigned types — widened both operands". Это предупреждение все объясняет: компилятор, зная, что совпадение наборов битов не гарантирует равенство знакового и беззнакового выражения, сначала "расширяет" типы выражений

до того типа, чей диапазон целиком вмещает оба требуемых диапазона и лишь затем выполняет сравнение. Это обеспечивает правильный результат сравнения, но требует дополнительных ресурсов, поэтому компилятор выдает предупреждение.

Аналогичные действия компилятор выполнит при сравнении выражений типов

Word
и
SmallInt
, а также
LongInt
и
LongWord
. Тип Int64 не имеет беззнакового аналога, поэтому операнды этого типа при сравнении компилятор не "расширяет".

Явное приведение типов позволяет избавиться от операций по расширению типа и ограничиться побитовым сравнением (листинг 3.7. пример Compare2 на компакт-диске).

Листинг 3.7. Явное приведение типов при сравнении

procedure TForm1.Button1Click(Sender: TObject);

var

 X: Byte;

 Y: ShortInt;

begin

 Y := -1;

 X := Y;

 if X = Byte(Y) then Label1.Caption := 'Равно'

 else Label1.Caption := 'Не равно';

end;

При компиляции такого кода не выдается никаких предупреждений, но и результат сравнения будет неверным: Равно.

Примечание

Операции >, <, >= и <= тоже работают по-разному для знаковых и беззнаковых чисел. Пусть, например, сравниваются числа 01000000 и 11000000. В беззнаковом формате это 64 и 192, поэтому первое число меньше второго. А в знаковом это 64 и -64, т. е. первое число больше. Из-за этого для операций сравнения для знаковых и беззнаковых чисел в системе команд процессора существуют разные команды. В литературе, чтобы подчеркнуть это, часто используются различные названия операций в зависимости от формата: для знаковых чисел — "больше" и "меньше", для беззнаковых — "выше" и "ниже".

3.1.5. Неявное преобразование в цикле for

Рассмотрим программу (пример ForRange на компакт-диске), на форме которой находятся кнопка и панель, причем кнопка (это важно!) — не на панели, а на форме, а на панели нет никаких компонентов. Обработчик нажатия на кнопку выглядит следующим образом (листинг 3.8).

Листинг 3.8. Обработчик нажатия кнопки

procedure TForm1.Button1Click(Sender: TObject);

var

 I: Cardinal;

begin

 for I := 0 to Panel1.ControlCount - 1 do

Panel1.Controls[I].Tag := 1;

end;

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

for
не должен выполниться ни разу. Тем не менее нажатие на кнопку вызывает исключение Access violation.

При нулевом количестве компонентов на панели выражение

Panel1.ControlCount - 1
должно давать значение -1. Но поскольку переменная цикла имеет тип
Сardinal
, эта комбинация битов интерпретируется как 4 294 967 295, верхняя граница оказывается больше нижней, и цикл начинает выполняться, обращаясь к несуществующим элементам управления. Отсюда и ошибка.

Поделиться:
Популярные книги

Блуждающие огни 4

Панченко Андрей Алексеевич
4. Блуждающие огни
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Блуждающие огни 4

Я сделаю это сама

Кальк Салма
1. Магический XVIII век
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Я сделаю это сама

Флеш Рояль

Тоцка Тала
Детективы:
триллеры
7.11
рейтинг книги
Флеш Рояль

Боярышня Дуняша

Меллер Юлия Викторовна
1. Боярышня
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Боярышня Дуняша

Газлайтер. Том 8

Володин Григорий
8. История Телепата
Фантастика:
попаданцы
альтернативная история
аниме
5.00
рейтинг книги
Газлайтер. Том 8

Леди для короля. Оборотная сторона короны

Воронцова Александра
3. Королевская охота
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Леди для короля. Оборотная сторона короны

На границе империй. Том 10. Часть 1

INDIGO
Вселенная EVE Online
Фантастика:
космическая фантастика
попаданцы
5.00
рейтинг книги
На границе империй. Том 10. Часть 1

Черный Маг Императора 5

Герда Александр
5. Черный маг императора
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Черный Маг Императора 5

Невест так много. Дилогия

Завойчинская Милена
Невест так много
Любовные романы:
любовно-фантастические романы
7.62
рейтинг книги
Невест так много. Дилогия

Идеальный мир для Социопата 3

Сапфир Олег
3. Социопат
Фантастика:
боевая фантастика
6.17
рейтинг книги
Идеальный мир для Социопата 3

Повелитель механического легиона. Том VIII

Лисицин Евгений
8. Повелитель механического легиона
Фантастика:
технофэнтези
аниме
фэнтези
5.00
рейтинг книги
Повелитель механического легиона. Том VIII

Наследник павшего дома. Том I

Вайс Александр
1. Расколотый мир
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Наследник павшего дома. Том I

Крещение огнем

Сапковский Анджей
5. Ведьмак
Фантастика:
фэнтези
9.40
рейтинг книги
Крещение огнем

Камень Книга двенадцатая

Минин Станислав
12. Камень
Фантастика:
боевая фантастика
городское фэнтези
аниме
фэнтези
5.00
рейтинг книги
Камень Книга двенадцатая