Разделы
  Delphi
  C++
  PHP
  Windows
  Linux
 

Основы Delphi: 4. Операции над целыми числами



Целочисленные типы данных играют ключевую роль в создании любой программы, которая будет выполняться микропроцессором. Основные регистры процессора - целочисленные, а большинство команд работают именно с этими регистрами. Поэтому очень важно эффективно использовать операции над целыми числами. Большинство компиляторов уже имеют средства, позволяющие генерировать оптимальный код, однако программист должен рационально использовать операции над целыми числами и не создавать лишних действий в программе.

32-битный микропроцессор оптимально работает с 32-битными значениями, поэтому в языке Delphi рекомендуется использовать типы integer и cardinal для операций с целыми числами. Однако, остальные целочисленные типы также могут быть использованы, если необходимо особым образом определить некую область памяти.


Целочисленные типы

Далее представлены все целочисленные типы языка Delphi. В таблице указано сколько памяти занимает значение того или иного типа:

ТипОписаниеРазмер памятиЗначения
byteБеззнаковое целое1 байт0..255
shortintЗнаковое целое1 байт-128..127
wordБеззнаковое целое2 байта0..65535
smallintЗнаковое целое2 байта-32768..32767
cardinal
longword
Беззнаковое целое4 байта0..4294967295
или 0..232-1
integer
longint
Знаковое целое4 байта-2147483648..2147483647
или -231..231-1
int64Знаковое целое8 байт-9223372036854775808..9223372036854775807
или -263..263-1
uint64Беззнаковое целое8 байт0..18446744073709551615
или 0..264-1

Для того, чтобы определить в программе, сколько памяти занимает тот или иной тип, можно использовать функцию SizeOf:

program TypeSize;

{$APPTYPE CONSOLE}

begin
  WriteLn('byte:     ',SizeOf(byte));
  WriteLn('word:     ',SizeOf(word));
  WriteLn('cardinal: ',SizeOf(cardinal));
  WriteLn('uint64:   ',SizeOf(uint64));

  ReadLn;
end.

byte:     1
word:     2
cardinal: 4
uint64:   8


Структура целочисленного значения

Для типа byte со структурой все понятно: занимает один байт, от 0 до 255, т.е. от 00000000 до 11111111 в двоичном виде. В структуре числа нет информации о знаке числа, поэтому тип и называется - беззнаковый.

Для знакового типа shortint необходимо сохранять информацию о знаке - для этого достаточно одного старшего (первого слева) бита. Если он равен 0, то число - положительное (или равное нулю) и его значения варьируются от 0 до 127, т.е. от 00000000 до 01111111. Если старший бит равен 1, то число - отрицательно, и оставшиеся 7 бит являются разностью между числом 128 и модулем искомого числа (так называемый дополнительный код числа). Например:

-111111111
-211111110
-311111101
-12810000000

Остальные целочисленные типы требуют больше, чем 1 байт памяти. Для удобства байты значения в памяти записывают в обратном порядке. Например число 123456 типа integer, которое в двоичном и шестнадцатиричном виде записывается как

00000000000000011110001001000000

0001E240

в памяти будет представлено в виде

01000000 11100010 00000001 00000000

40       E2       01       00

Чтобы убедиться в том, что байты значения в памяти записываются в обратном порядке можно провести эксперимент. Возьмем у числа 789 (или 0000001100010101) типа word только первый байт, и он должен равняться 21 (или 00010101), а не 3 (или 00000011) при прямом порядке:

program ByteOrder;

{$APPTYPE CONSOLE}

var
  A: word;
  P: pointer;

begin
  A := 789;
  P := @A; // указатель на область памяти переменной A

  WriteLn( A );
  WriteLn( PByte(P)^ ); // выводим первый байт области памяти
                        // на который указывает P
  ReadLn;
end.

789
21


Операции

Операции над целыми числами можно разделить на арифметические и побитовые. Арифметические операции представлены в следующей таблице:

ЗнакОперацияПримерРезультат
+Сложение7 + 411
-Вычитание7 - 43
*Умножение7 * 428
/Деление7 / 41.75 (всегда вещественное)
divДеление без остатка7 div 41 (всегда целое)
modОстаток от деления7 mod 43

Побитовые (bitwise) операции отличаются от арифметических тем, что взаимодействуют не сами числа, а соответствующие биты. Для каждой пары битов выполняется какая-либо логическая операция, и результат побитовой операции будет составляться из результатов логических операций для каждой пары бит.

ЗнакОперацияПримерРезультат
notОтрицаниеnot 5 (¬ 00000101)-6 (11111010)
andПобитовое логическое "И"5 and 7 (00000101 ^ 00000111)5 (00000101)
orПобитовое логическое "ИЛИ"5 or 7 (00000101 v 00000111)7 (00000111)
xorПобитовое логическое "исключающее ИЛИ"5 xor 7 (00000101 xor 00000111)2 (00000010)
shlСдвиг битов влево22 shl 2 (00010110)88 (01011000)
shrСдвиг битов вправо22 shr 2 (00010110)5 (00000101)


Приведение типов

Значения одного целочисленного типа приводятся к другому целочисленному типу без каких либо проблем. Следует учесть, что если новый тип занимает в памяти меньше байт, чем старый тип, то лишние байты просто отсекаются. Это также удобно, если необходимо получить первые несколько байт целочисленного значение (например, первый байт значения типа word или первые два байта значения типа cardinal). Однако, если тип значения знаковый, а само значение отрицательное, то приведение к типу, занимающему меньше памяти, может привести к положительному результату. Например, приводя значение -1000 (11111100 00011000) типа smallint к типу shortint, в результате получим 24 (00011000).

Значение результата какой-либо целочисленной операции всегда имеет тип, который занимает в памяти максимум из типов операндов. Например, integer + word = integer, int64 - byte = int64. Это может создать проблемы при операции умножения, когда результат необходимо получить с типом int64. В конструкции

var
  a, b: integer;
  c: int64;

...

  c := a * b;

выражение (a * b) имеет тип integer, а не int64, и значение может переполниться. В этом случае следует привести один из операндов к типу int64. Явное приведение к какому-либо типу описывается следующим образом:

<тип> ( <выражение> )

В таком случае, текст программы выглядит так:

var
  a, b: integer;
  c: int64;

...

  c := int64(a) * b;





Copyright (C) ZasKok S.M.S., 2009-2010
Hosted by uCoz