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

на главную - закладки

Жанры

О чём не пишут в книгах по 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, верхняя граница оказывается больше нижней, и цикл начинает выполняться, обращаясь к несуществующим элементам управления. Отсюда и ошибка.

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

Измена. (Не)любимая жена олигарха

Лаванда Марго
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Измена. (Не)любимая жена олигарха

Хозяйка дома в «Гиблых Пределах»

Нова Юлия
Любовные романы:
любовно-фантастические романы
5.75
рейтинг книги
Хозяйка дома в «Гиблых Пределах»

Фиктивный брак

Завгородняя Анна Александровна
Фантастика:
фэнтези
6.71
рейтинг книги
Фиктивный брак

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

INDIGO
8. Фортуна дама переменчивая
Фантастика:
космическая фантастика
попаданцы
6.13
рейтинг книги
На границе империй. Том 7. Часть 2

Держать удар

Иванов Дмитрий
11. Девяностые
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Держать удар

Флеш Рояль

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

Драконий подарок

Суббота Светлана
1. Королевская академия Драко
Любовные романы:
любовно-фантастические романы
7.30
рейтинг книги
Драконий подарок

Зауряд-врач

Дроздов Анатолий Федорович
1. Зауряд-врач
Фантастика:
альтернативная история
8.64
рейтинг книги
Зауряд-врач

По дороге на Оюту

Лунёва Мария
Фантастика:
космическая фантастика
8.67
рейтинг книги
По дороге на Оюту

Мастер 5

Чащин Валерий
5. Мастер
Фантастика:
попаданцы
аниме
5.00
рейтинг книги
Мастер 5

Не лечи мне мозги, МАГ!

Ордина Ирина
Фантастика:
городское фэнтези
попаданцы
фэнтези
5.00
рейтинг книги
Не лечи мне мозги, МАГ!

Измена. Право на семью

Арская Арина
Любовные романы:
современные любовные романы
5.20
рейтинг книги
Измена. Право на семью

Крепость над бездной

Лисина Александра
4. Гибрид
Фантастика:
боевая фантастика
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Крепость над бездной

Неудержимый. Книга XXI

Боярский Андрей
21. Неудержимый
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Неудержимый. Книга XXI