Comp — Тип Delphi
Любой реально существующий тип данных, каким бы сложным он ни казался на первый взгляд, представляет собой простые составляющие, которыми процессор может манипулировать. В Object Pascal эти простые типы данных разбиты на две группы: порядковые, представляющие данные разных объемов, которыми процессор может легко манипулировать, и действительные, представляющие приближенно математические действительные числа. Разделение типов на порядковые и действительные несколько условно. Точно так же простые данные можно было бы разделить на числа и не числа. Однако в языке Object Pascal порядковые и действительные данные трактуются по-разному, и такое разделение даже полезно.
Порядковые типы
Для всех порядковых типов в Object Pascal существует операция задания типа для преобразования целых значений в значения соответствующих порядковых типов. Если Т — имя порядкового типа, а Х — целое выражение, то Т (X) воз-вращает значение Т с порядковым номером X.
Совет: Программисты, работающие на С и C++, для приращения или уменьшения значений переменных привыкли заметку использовать операторы «++» и «—«, возвращающие следующее и предыдущее значения. Программисты Delphi всегда разбивают эти операции на более простые составляющие с помощью функций Pred, Succ. Dec и Inc.
Таблица 1.1. Операции над порядковыми типами
Операция | Описание |
Low (T) | Минимальное значение порядкового типа Т |
High(T) | Максимальное значение порядкового типа Т |
Ord(X) | Порядковый номер значения выражения порядкового типа. Для целого выражения — просто его значение. Для остальных порядковых типов Ord возвращает физическое представление результата выражения, трактуемое как целое число. Возвращаемое значение всегда принадлежит одному из целых типов |
Pred(X) | Предыдущее по порядку значение. Для целых выражений эквивалентно Х-1 |
Succ(X) | Следующее по порядку значение. Для целых выражений эквивалентно Х+1 |
Dec(V) | Уменьшает значение переменной на 1. Эквивалентно V := Pred(V) |
Inc(V) | Увеличивает значение переменной на 1. Эквивалентно V := Succ(V) |
Целые типы
Обратите внимание, что один из этих целых типов назван именно целым (integer). Это может иногда приводить к путанице, но мы легко сможем ее избежать, применяя термин целый к. группе типов, a integer — к конкретному типу, определяемому в программе этим ключевым словом. Переменные физических целых типов имеют разные диапазоны значений в зависимости от того, сколько байтов памяти они занимают (что равно значению, возвращаемому функцией SizeOf для данного типа). Диапазоны значений для всех физических типов перечислены в табл. 1.2.
Таблица 1.2. Физические целые типы
Тип | Диапазон значении | Физический формат |
Shortint | -128-127 | 8 бит, со знаком |
Smallint | -32 768-32 767 | 16 бит, со знаком |
Longint | -2 147 483 648-2 147 483 647 | 32 бит, со знаком |
Byte | 0-255 | 8 бит, без знака |
Word | 0-65 535 | 16 бит, без знака |
Тип | Диапазон значений | Физический формат |
Integer | -32 768-32 767 | 16 бит, со знаком (SmalIInt) |
Integer | -2 147 483 648-2 147 483 647 | 32 бит, со знаком (Longint) |
Cardinal | 0-65 535 | 16 бит, без знака (Word) |
Cardinal | 0-2 147483647 | 32 бит, без знака (Longint) |
Совет: В С и C++ для целых значений определены типы int, short int (или просто short) и long int (или просто long). Тип int из C/C++ соответствует типу Integer из Delphi, a long из C/C++ — Longint из Delphi. Однако Shortint из C/C++ соответствует в Delphi не Shortint, a Smalltlnt. Эквивалент Shortint из Delphi в C/C++- это signed char. Тип unsigned char в C/C++ соответствует типу Byte из Delphi. В C/C++ существует еще тип unsigned long, аналога которому в Delphi нет.
Над целыми данными выполняются все операции, определенные для порядковых типов, но с ними все же удобнее работать как с числами, а не с «нечисленными порядковыми типами». Как и «живые» числа, данные целых типов можно складывать (+), вычитать (-) и умножать (*). Однако некоторые операции и функции, применяемые к данным целых типов, имеют несколько иной смысл.
Операция | Результат |
Abs (X) | Возвращает абсолютное целое значение Х |
Х Div Y | Возвращает целую часть частного деления Х на Y |
Х Mod Y | Возвращает остаток частного деления Х на Y |
Odd (X) | Возвращает булево True (истина), если Х — нечетное целое, и False (ложь) — в противном случае |
Sqr (X) | Возвращает целый квадрат Х (т.е. Х*Х) |
Символьные типы
AnsiChar | Однобайтовые символы, упорядоченные в соответствии с расширенным набором символов ANSI |
WideChar | Символы объемом в слово, упорядоченные в соответствии с международным набором символов UNICODE. Первые 256 символов совпадают с символами ANSI |
Chr (X) | Преобразует целую переменную в переменную типа char с тем же порядковым номером. В Delphi это эквивалентно заданию типа Char (X) |
UpCase | Преобразует строчную букву в прописную |
Булевы типы
Тип | Размер |
Boolean | 1 байт |
ByteBool | 1 байт |
WordBool | 2 байт (объем Word) |
LongBool | 4 байт (объем Longint) |
Совет: Булевы типы в Delphi можно сравнить с типом LOGICAL языка FORTRAN. В Basic, С и C++ булевы типы как таковые отсутствуют. Булевы выражения в этих языках применяются точно так же, как во всех остальных, однако результаты этих выражений интерпретируются не как значения отдельного типа, а как целые числа. Как в Basic, так и в C/C++ булевы выражения дают численные результаты, интерпретируемые как False в случае 0 и True — в случае любого ненулевого значения. Это совместимо с порядковыми значениями булевых выражений в Delphi. В C/C++ простые сравнения дают результат 1 (True) или 0 (False). Это эквивалентно булевым значениям Delphi. Только результат сравнения в Delphi выводится как булевый, а не целый. В большинстве случаев типу Boolean из Delphi соответствует тип char в C/C++. В Basic зарезервированы слова TRUE (эквивалентно константе -1) и FALSE (эквивалентно константе 0). В Basic TRUE меньше FALSE, в Delphi, наоборот, False меньше True.
Перечислимые типы
Совет: В С и C++ есть тип enema, аналогичный перечислимому типу Delphi. Но в этих языках можно произвольно присваивать идентификаторам постоянные значения. В Delphi же соответствие имен и их значений фиксиро-вано: первому имени присваивается значение 0, каждому последующему — на единицу больше. В С тип enum применяется лишь как средство быстрого определения набора целых постоянных. В C++ объявленные в перечислимом типе идентификаторы можно присваивать только переменным того же типа.
Поддиапазонные типы
Type subrange type = low value. high value;
Поддиапазонные переменные сохраняют все особенности исходного типа. Единственное отличие состоит в том, что переменной поддиапазонного типа можно присваивать только значения, входящие в заданный поддиапазон. Контроль за соблюдением этого условия задается командой проверки диапазона (range checking).
Необходимость явно определять поддиапазонный тип возникает нечасто, но все программисты неявно применяют эту конструкцию при определении массивов. Именно в форме поддиапазонной конструкции задается схема нумерации элементов массива.
Действительные типы
Тип | Порог | Максимальное значение | Количество значащих цифр | Объем (байт) |
Real | 2.9E-39 | 1.7Е38 | 11-12 | 6 |
Single | 1.5E-45 | 3.4Е38 | 7-8 | 4 |
Double | 5.0E-324 | 1.7Е308 | 15-16 | 8 |
Extended | 3.4E-4932 | 1.IE4932 | 19-20 | 10 |
Comp | 1.0 | 9.2Е18 | 19-20 | 8 |
Currency | 0.0001 | 9.2Е14 | 19-20 | 8 |
Совет: Тип Real предназначен для совместимости с ранними версиями Delphi и Borland Pascal. Формат этого типа неудобен для семейства процессоров Intel, поэтому операции с типом Real выполняются несколько медленнее операций над остальными действительными типами.
Целые типы представляют целые числа, т.е. числа, дробная часть которых равна нулю. Разница между двумя неодинаковыми целыми числами не может быть меньше единицы. Именно благодаря этому целые числа применяются для обозначения дискретных величин, независимо от того, имеют ли реальные объекты какое-либо отношение к числам. Действительные типы предназначены для представления чисел, которые могут иметь дробную часть, поэтому они полезны для представления величин, которые могут быть довольно близкими, почти непрерывными.
Заметьте, именно почти. Несмотря на название действительные, переменные этих типов отличаются от математических действительных чисел. В Object Pascal действительный тип — это подмножество математических действительных чисел, которые можно представить в формате с плавающей запятой и фиксированным числом цифр. Для невнимательных программистов ситуация усугубляется тем, что в стандартных форматах IEEE (Institute of Electrical and Electronic Engi-neers — Институт инженеров- электриков и электронщиков), применяемых в программах Delphi и вообще в большинстве программ для Windows, возможно точное представление только чисел с фиксированным числом бит в дробной части. Удивительно, но такое простое число, как 0,1, записывается в расширенном формате IEEE с некоторой погрешностью, пусть очень небольшой. Из-за этого представление с плавающей запятой оказывается несколько неудобным для программ, в которых сохраняется и выводится фиксированное число десятичных разрядов численных значений. Это относится и к программам, работающим с »живыми» деньгами.
Для частичного решения этой проблемы в Object Pascal определены два формата с фиксированной запятой. Тип Comp (computational — вычислительный) содержит только целые числа в диапазоне от -2 63 +1 до 2 63 -1, что примерно соответствует диапазону от -9,2х10 18 до 9,2х10 18 . При программировании операций с американской валютой разработчикам обычно приходится искать естественный способ записи денежных сумм, в котором целая часть числа определяет количество долларов, дробная — центов. Если такие значения записывать в переменные типа Comp, придется представлять их в виде целого числа центов. В этом случае следует умножать значение на 100 для обращения центов в доллары, а затем делить на 100, чтобы снова получить центы.
Этих забот можно избежать, если воспользоваться типом Currency. В этом случае задачу выбора масштаба возьмет на себя компилятор. Физически значения Currency записываются в память того же объема, что и Comp, как целые числа, однако компилятор не забывает вовремя разделить значение на 10 000 (не на 100!) для его приведения в соответствие с денежным знаком и умножить на 10 000 перед записью в память. Это обеспечивает абсолютную точность в четыре десятичных знака после запятой.
В Delphi есть модуль System, содержащий ряд процедур обработки данных действительных типов. Наиболее распространенные из них перечислены в табл. 1.6. Много полезных процедур содержится также в модулях SysUtils и Math.
Таблица 1.6. Функции действительных типов
Функция | Возвращаемое значение |
Abs (x) | Абсолютная величина х |
АгсТаn(х) | Арктангенс х |
Cos (х) | Косинус х (х выражается в радианах, а не в градусах) |
Ехр (х) | Экспоненциальная функция от х |
Frac(x) | Дробная часть х |
Int (х) | Целая часть х. Несмотря на название, возвращает действительное значение (с плавающей запятой), т.е. просто устанавливает нуль в дробной части |
Ln (х) | Натуральный логарифм от х |
Pi | Число Пи (3.1416. ) |
Round (х) | Ближайшее к х целое значение. Возвращает значение целого типа. Условие «ближайшее к х» не работает, если верхнее и нижнее значения оказываются равноудаленными (например, ес-ли дробная часть точно равна 0,5). В этих случаях Delphi перекладывает решение на опера-ционную систему. Обычно процессоры Intel решают эту задачу в соответствии с рекоменда-цией IEEE округлять в сторону ближайшего четного целого числа. Иногда такой подход на-зывают «банкирским округлением» |
Sin(x) | Синус х |
Sqr(x) | Квадрат х, т.е. X*X |
Sqrt (х) | Квадратный корень от х |
Тrunc (х) | Целая часть х. В отличие от Int, возвращающей действительное значение, Trunc возвращает целое |
Совет: Будьте внимательны при переносе численных выражений из одного языка в другой. В Basic функция SQR вычисляет квадратный корень, а функция Sqr из Delphi — квадрат числа. Для вычисления квадратного корня в Delphi применяется функция Sqrt.
Оглавление
DelphiComponent.ru — бесплатно видеоуроки по Delphi, статьи, исходники
Вещественные типы (Действительные типы) в Delphi XE
Значение переменных вещественного типа всегда приблизительные, поэтому их нельзя проверять на равенство!
-2.9×10 -39 ..1.7×10 38
-1.5×10 -45 ..3.4×10 38
-5.0×10 -324 ..1.7×10 3U8
-3.6×10 -4951 «1.1×10 4y32
-2×10 63 +1 ..2×10 63 -1
Тип Real 48 оставлен только для совместимости с предыдущими версиями Delphi , поэтому его не следует использовать.
Типы Comp и Currency используются только в денежных операциях.
Обычно для расчётов хватает точности типа Single , но вычисления производятся быстрее с типом Real (он же Double ).
Для записи вещественных чисел используют 2 способа. Первый — как в школе, но вместо десятичной запятой ставится точка:
Для очень больших и очень маленьких чисел больше подходит второй способ. Сначала записывается однозначное число с десятичной точкой, затем буква E (или е) и целое число, которое равно степени десятки. Например,
Объявление переменных вещественного типа:
Вещественные числа часто используются для «технических» расчётов, а при необходимости их можно округлить до целых чисел (тип результата — int 64) с помощью функций trunc и round .
Целым переменным нельзя присваивать действительные значения!
Функция trunc просто отсекает дробную часть числа:
Функция round округляет действительное число до ближайшего целого:
Чтобы было легче понять, как действует функция round , выразим её через trunc :
Comp — Тип Delphi
Доброго времени суток, уважаемые подписчики!
Сегодня публикуется статья Сысоева Александра Петровича о строковых типах в Delphi.
В этой статье будут освещены следующие вопросы:
- Какие строковые типы существуют в Delphi, и чем они отличаются друг от друга
- Преобразование строк из одного типа в другой
- Некоторые приемы использования строк типа AnsiString:
- Функции для работы со строками о которых многие часто забывают или вовсе не знают
- Передача строк в качестве параметров
- Использование строк в записях
- Запись в файл и чтение из файла
- Использование строк в качестве параметров и результатов функций размещенных в DLL.
Ну что, интересно? Тогда поехали.
Какие строковые типы существуют в Delphi, и чем они отличаются друг от друга?
В Delphi 1.0 существовал лишь единственный строковый тип String, полностью эквивалентный одноименному типу в Turbo Pascal и Borland Pascal. Однако, этот тип имеет существенные ограничения, о которых я расскажу позднее. Для обхода этих ограничений, в Delphi 2, разработчики из Borland устроили небольшую революцию. Теперь, начиная с Delphi 2, имеются три фундаментальных строковых типа: ShortString, AnsiString, и WideString. Кроме того, тип String теперь стал логическим. Т.е., в зависимости от настройки соответствующего режима компилятора (режим больших строк), он приравнивается либо к типу ShortString (для совместимости со старыми программами), либо к типу AnsiString (по умолчанию). Управлять режимом, можно используя директиву компиляции <$LONGSTRINGS ON/OFF>(короткая форма <$H+/->) или из окна настроек проекта — вкладка «Compiler» -> галочка «Huge strings». Если режим включен, то String приравнивается к AnsiString, иначе String приравнивается ShortString. Из этого правила есть исключение: если в определении типа String указан максимальный размер строки, например String[25], то, вне зависимости от режима компилятора, этот тип будет приравнен к ShortString соответствующего размера.
Поскольку, как вы узнаете в дальнейшем, типы ShortString и AnsiString имеют принципиальное отличие в реализации, то я вообще не рекомендую пользоваться логическим типом String без указания размера, если Вы, конечно, не пишете программ под Delphi 1. Если же Вы все-таки используете тип String, то я настоятельно рекомендую прямо в коде Вашего модуля указывать директиву компиляции, устанавливающую подразумеваемый Вами режим работы компилятора. Особенно если Вы используете особенности реализации соответствующего строкового типа. Если этого не сделать, то однажды, когда Ваш код попадет в руки другого программиста, не будет никакой гарантии того, что его компилятор будет настроен, так же как и Ваш.
Поскольку по умолчанию, после установки Delphi, режим больших строк включен, большинство молодых программистов даже и не подозревают, что String может представлять что-то отличное от AnsiString. Поэтому, дальше в этой статье, любое упоминание типа String без указания размера, подразумевает, что он равен типу AnsiString, если не будет явно указано иное. Т.е., считается что настройка компилятора соответствует настройке по умолчанию.
Сразу же упомяну о различии между типами AnsiString и WideString. Эти типы имеют практически одинаковую реализацию, и отличаются лишь тем, что WideString используется для представления строк в кодировке UNICODE использующей 16-ти битное представление каждого символа (WideChar). Эта кодировка используется в тех случаях когда необходима возможность одновременного присутствия в одной строке символов из двух и более языков (помимо английского). Например, строк содержащих одновременно символы английского, русского и европейских языков. За эту возможность приходится платить — размер памяти, занимаемый такими строками в два раза больше размера, занимаемого обычными строками. Использование WideString встречается не часто, поэтому, я буду в основном рассказывать о строках типа AnsiString. Но, поскольку они имеют одинаковую реализацию, почти все сказанное относительно AnsiString будет действительно и для WideString, естественно с учетом разницы в размере каждого символа.
Тоже самое касается и разницы между pChar и pWideChar.
Строковый тип AnsiString, обычно используется для представления строк в кодировке ANSI, или других (например OEM) в которых для кодирования одного символа используется один байт (8 бит). Такой способ кодирования называется single-byte character set, или SBCS. Но, очень многие не знают о существовании еще одного способа кодирования многоязычных строк (помимо UNICODE) используемого в системах Windows и Linux. Этот способ называется multibyte character sets, или MBCS. При этом способе, некоторые символы представляются одним байтом, а некоторые, двумя и более. В отличие от UNICODE, строки, закодированные таким способом, требуют меньше памяти для своего хранения, но требуют более сложной обработки. Так вот, строковый тип AnsiString может использоваться для хранения таких строк. Я не буду подробно останавливаться на этом способе кодирования, поскольку он применяется крайне редко. Лично я, ни разу не встречал программ использующих данный способ кодирования.
Знатоки Delphi вероятно мне сразу напомнят еще и о типах pChar (pWideChar) и array [. ] of Char. Однако, я считаю, что это не совсем строковые типы, но я расскажу и о них, поскольку они очень часто используются в сочетании со строковыми типами.
Итак, приведу основные характеристики строковых типов:
Тип | Максимальный размер строки | Размер переменной | Объем памяти, требуемый для хранения строки | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
String[n] где 0 позволяет легко определить реальный размер строки на которую указывает значение pChar.
Не смотря на то, что формально pChar это указатель на Char (^Char), как это часто бывает в Delphi, тип pChar имеет несколько особенностей по сравнению с другими указателями. Таких особенностей несколько. Первая, заключается в том что константы, и глобальные переменные этого типа могут быть проинициализированы строковой константой. Вот пример: Эти строки, определяют константу pc и переменную pv типа pChar. При этом, и pc и pv указывают на разные области памяти, но содержащие одинаковые значения, состоящие из трех символов: ‘a’, ‘b’, ‘c’, и символа #0. Замечу, что завершающий символ с кодом 0 компилятор добавил автоматически. Вторая особенность в том, что к переменным типа pChar применимо обращение как к массиву символов. Например, если есть приведенные выше определения, тогда: Замечу, символ с индексом 3 отсутствует в строке, однако, там есть завершающий ее символ с кодом 0. Именно он будет результатом pv[3]. О pv[4] тоже стоит сказать особо. Дело в том, что компилятор не даст ошибки при компиляции, поскольку на этапе компиляции он, в общем случае, не известен реальный размер строки, на которую указывает переменная pv. Однако, на этапе выполнения программы, такое обращение может вызвать ошибку нарушения доступа к памяти (Access Violation). А может и не вызвать, но результатом будет неопределённое значение. Все зависит от в памяти. Поэтому, при таком способе обращения необходимо быть внимательным, и выполнять все необходимые проверки, исключающие выход за размеры строки. Третья и последняя особенность типа pChar в том, что к значениям этого типа применима так называемая адресная арифметика. Тем, кто программирует на C и C++ она хорошо знакома. Суть её в том, что значения pChar можно увеличивать, уменьшать, вычитать, и складывать. Для демонстрации использования этой особенности, приведу пример реализации функции подсчитывающей длину строки, указатель на которую передается в качестве параметра. Здесь важно обратить внимание на два нюанса. Первый, это проверка переданного указателя на nil. Такая проверка необходима, поскольку очень часто, для обозначения пустой строки используется значение nil. Второй, это оператор Inc(p) — он указатель на следующий символ. Можно было бы записать его и так: p := p + 1. Что бы продемонстрировать вычитание указателей pChar, я приведу еще один вариант реализации той же функции: Здесь, выражение pp-p дает между указателями, т.е. число символов между символом, на который указывает указатель p (начало строки) и символом, на который указывает указатель pp (завершающий строку #0). На этом, мы пока закончим рассмотрение типа pChar, но, он еще встретится, когда мы будем рассматривать вопросы преобразования строковых типов. ShortString, и String[n]ShortString является частным случаем String[n], а если быть более точным, он полностью эквивалентен String[255]. Если посмотреть на таблицу, где приведены характеристики переменных этого типа, то мы увидим что их размер на один байт больше чем размер хранимой в них строки. Но в данном случае, это не для завершающего символа, как в pChar. Здесь в дополнительном байте хранится текущий размер строки. Кроме того, этот байт располагается не в конце строки, а наоборот, в ее начале. К примеру, если имеется следующее определение: Оно означает, что для переменной s будет статически выделена область памяти размером 5 байт. Теперь, выполнение оператора s := ‘abc’, приведёт к тому, что содержимое этих пяти байт станет следующим: байт 1 = 3, байт 2 = ‘a’, байт 3 = ‘b’, байт 4 = ‘c’, а значение байта 5 будет неопределённо — оно будет зависеть от в памяти. Т.е., первый символ строки будет находиться во втором байте. Это неудобно, поэтому к символам строк ShortString принято индексироваться, начиная с 1. Следовательно: А как же байт длины? Да все очень просто, к нему можно обратиться как s[0]. Только вот есть маленькая проблемка. Поскольку элементами строки являются символы, то и тип значения s[0] тоже будет символ. Т.е., если Вы хотите получить длину строки в виде целого числа, как это принято у нормальных людей, то надо выполнить соответствующее преобразование типа: Ord(s[0]) = 3 — размер строки. Теперь, я думаю, Вам станет ясно, почему для типа String[n] существует ограничение 0 Строки этого типа объединили в себе ряд качеств как строк ShortString и их байтом длины, так и строк завершающихся нулем (pChar). Последнее было необходимо, поскольку к моменту их появления, засилье C-ишников было уже так велико :), что большинство системных функций Windows API оперировало строками именно такого формата. А если серьезно, то такой формат строк хоть и более трудоемок в обработке, зато в принципе лишен ограниченности на максимальный размер строки. Ведь хранение размера строки всегда ограниченно какими-либо рамками: если хранить в байте, то ограничение 255 байт; если хранить в слове, то ограничение 65535 символов; и т.д. Однако, совсем отказываться от хранения текущей длинны строки в Borland не стали. Но об этом позже. Напомню, что еще одним из недостатков статически размещаемых строк ShortString было «расточительство». Т.е. определив переменную такого типа, мы заранее резервировали под нее 256 байт памяти, поэтому, если мы один раз, во всей программе, присвоили ей значение ‘abcd’, то 251 байт памяти мы просто . Казалось бы, а зачем так определили, написали бы String[4], и ничего не потеряли бы. Но, когда мы пишем программу, мы же чаще всего не знаем что мы будем в эту переменную. Вот и определяем с запасом. Решением этой проблемы стало использование динамически размещаемых строк. Так как они устроены?Если вы обратили внимание, в таблице характеристик строковых типов, размер переменных AnsiString равен четырем байтам, как и у pChar. Это говорит нам о том, что переменные этого типа тоже являются указателями. Но, в отличие от pChar, в данном случае, это скрыто реализацией. Т.е. программист, работает с ними как с обычными строками: не надо выделять под них память, не надо заботиться о наличии завершающего нуля, не надо волноваться об изменении размеров строки и т.п. Всю эту работу берет на себя компилятор Delphi. Более того, он ещё и занимается оптимизациями. В частности, если например выполнить следующий код: то в памяти будет храниться лишь ОДИН экземпляр строки ‘abc’! Во как. Как же это происходит?При выполнении первого оператора (присваивание s1), указатель, хранящийся в переменной s1 настраивается на область памяти в которой размещена строка ‘abc’. При выполнении второго оператора, в s2 попадает тот же адрес! Т.е. в памяти при это присутствует лишь один экземпляр строки ‘abc’. Да и зачем нам нужны дублирующие себя строки. Не нужно программисту заботиться и об освобождении памяти занятой ненужными уже строками. Вот например есть такая процедура: Здесь, при выполнении присваивания, Delphi создаст в памяти экземпляр строки ‘Значение переменной равно 123’, и присвоит адрес этой строки переменной s. Однако, при завершении процедуры, переменная s перестанет существовать — она же локальная. Значит, и экземпляр строки тоже уже не нужен — на него некому будет указывать. Вот поэтому, Delphi автоматически освободит память, выделенную под строку, как только, выполнение процедуры достигнет строки end. Более того, даже если во время выполнения процедуры возникнет исключительная ситуация, при которой «хвост» процедуры может и не выполниться, Delphi всё равно корректно освободит память для всех строк, распределенных в этой процедуре. Достигается это неявным использованием механизма подобного try — finally. Казалось бы, всё замечательно. Но попробуем усложнить ситуацию. Теперь, к моменту завершения процедуры, на экземпляр строки ‘Значение переменной равно 123’ уже ссылаются две переменные s и gs. И, несмотря на то, что область существования переменной s заканчивается, освобождать память, выделенную под строку на которую она указывает нельзя! Ведь позже, возможны обращения к переменной gs. Для того, чтобы корректно обрабатывать такие ситуации, Delphi для каждой динамически распределенной строки ведет так называемый «счётчик ссылок». Т.е., как только он присваивает какой-либо из строковых (AnsiString) переменных ссылку на распределенную в памяти строку, то он увеличивает этот счетчик на единицу. Первоначально, при присваивании динамически распределённой строки, первой переменной (в примере s), значение этого счётчика устанавливается равным единице. В последствии, при прекращении жизни каждой строковой переменной, он уменьшает на 1 этот счетчик для той строки на которую она указывает. Если счётчик становится равным 0, то значит более нет строковых переменных, указывающих на данную строку. Значит, ее можно освобождать. Благодаря такому алгоритму, после присваивания в примере значения переменной gs, у строки ‘Значение переменной равно 123’ счетчик ссылок становится равным 2. Следовательно, при «умирании» переменной s, он декрементируется, и становится равным 1. Т.е. >0, поэтому то Delphi и не освобождает память, занятую строкой. Еще, этот счётчик используется и для разрешения проблем, связанных со следующей ситуацией: Здесь, как мы уже знаем, после выполнения оператора s2 := s1, обе переменные указывают на один и тот же экземпляр строки ‘abc123’. Однако, что же произойдёт когда выполниться оператор s2[1] := ‘X’? Казалось бы, в единственном имеющимся в нашем распоряжении экземпляре строки первая буква будет заменена на ‘X’. И как следствие, обе строки станут равными ‘Xbc123’. s1 то за что «страдает»? Но, к счастью это не так. Здесь на помощь Delphi вновь приходит счетчик ссылок. Delphi, при выполнении этого оператора понимает, что строка на которую указывает s2 будет изменена, а это может повлиять на других. Поэтому, перед изменением строки, проверяется ее счётчик ссылок. Обнаружив, что на нее ссылается более одной строковой переменной, делается следующее: создается копия этой строки со счётчиком ссылок равным 1, и адрес этой копии, присваивается s2; У исходного экземпляра строки, счетчик ссылок уменьшается на 1 — ведь s2 на неё теперь не ссылается. И лишь после этого, происходит изменение первой буквы, теперь уже собственного экземпляра строки. Т.е., по окончанию выполнения этого оператора, в памяти будут находиться две строки: ‘abc123’ и ‘Xbc123’. Причем, s1 будет ссылаться на первую, а s2 на вторую. При работе со строками определенными как константы, алгоритм работы несколько отличается. Приведу пример: Казалось бы, при завершении работы процедуры, экземпляр строки ‘Вася’ должен быть уничтожен. Но в данном случае это не так. Ведь, при следующем входе в процедуру, для выполнения присваивания нужно будет вновь где-то взять строку ‘Вася’. Для этого, ещё при компиляции, Delphi размещает экземпляр строки ‘Вася’ в области констант программы, где её даже невозможно изменить, по крайней мере, простыми методами. Но как же при завершении процедуры определить что строка ‘Вася’ — константная строка, и ее нельзя уничтожать? Все очень просто. Для константных строк, счётчик ссылок устанавливается равным -1. Это значение, «выключает» нормальный алгоритм работы со «счётчиком ссылок». Он не увеличивается при присваивании, и не уменьшается при уничтожении переменной. Однако, при попытке изменения переменной (помните s2[1]:=’X’), значение счётчика равное -1 будет всегда считаться признаком того, что на строку ссылается более одной переменной (ведь он не равен 1). Поэтому, в такой ситуации всегда будет создаваться уникальный экземпляр строки, естественно, без декремента счётчика ссылок старой. Это защитит от изменений экземпляр строки-константы. К сожалению, этот алгоритм срабатывает не всегда. Но об этом, мы поговорим позже, при рассмотрении вопросов преобразования строковых типов. Где же Delphi хранит «счётчик ссылок»? Причем, для каждой строки свой! Естественно, вместе с самой строкой. Вот что представляет собой эта область памяти, хранящая экземпляр строки ‘abc’:
Для удобства работы с такой структурой, когда строковой переменной присваивается ссылка на эту строку, в переменную заносится адрес не начала этой структуры, а адрес её девятого байта. Т.е. адрес начала реальной строки (прямо как pChar). Для того, что бы приблизиться к реальной жизни, перепишем приведённую структуру:
С полем по смещению -8, нам уже должно быть все ясно. Это значение, хранящееся в двойном слове (4 байта), тот самый счетчик, который позволяет оптимизировать хранение одинаковых строк. Значение этого счетчика имеет тип Integer, т.е. может быть отрицательным. На самом деле, используется лишь одно отрицательное значение — «-1», и положительные значения. 0 не используется. Теперь, обратите внимание на поле, лежащее по смещению -4. Это, четырёхбайтовое значение длинны строки (почти как в ShortString). Думаю, Вы заметили, что размер памяти выделенной под эту строку не имеет избыточности. Т.е. компилятор выделяет под строку минимально необходимое число байт памяти. Это конечно хорошо, но, при попытке «нарастить» строку: s1 := s1 + ‘d’, компилятору, точнее библиотеке времени исполнения (RTL) придется перераспределить память. Ведь теперь строке требуется больше памяти, аж на целый байт. Для перераспределения памяти нужно знать текущий размер строки. Вероятно, именно для того, что бы не приходилось каждый раз сканировать строку, определяя её размер, разработчики Delphi и включили поле длины, строки в эту структуру. Длина строки, хранится как значение Integer, отсюда и ограничение на максимальный размер таких строк — 2 Гбайт. Надеюсь, мы не скоро упрёмся в это ограничение. Кстати, именно потому, что память под эти строки выделяется динамически, они и получили ещё одно свое название: динамические строки. Осталось рассказать ещё о нескольких особенностях переменных AnsiString. Важнейшей особенностью значений этого типа является возможность приведения их к типу Pointer. Это впрочем, естественно, ведь в «душе» они и есть указатели, как бы они этого не скрывали. Например, если описаны переменные: s :AnsiString и p :Pointer. То выполнение оператора p := Pointer(s) приведет к тому, что переменная p станет указывать на экземпляр строки. Однако, при этом, очень важно знать: счетчик ссылок этой строки не будет увеличен. Но об этом, мы поговорим чуть позднее. Поскольку, переменные этого типа реально являются указателями, то для них и реально такое значение как Nil — указатель в «никуда». Это значение в переменной типа AnsiString по смыслу приравнивается пустой строке. Более того, чтобы не тратить память и время на ведение счётчика ссылок, и поля размера строки всегда равного 0, при присваивании пустой строке переменной этого типа, реально, присваивается значение Nil. Это не очевидно, поскольку обычно не заметно, но как мы увидим позже, очень важная особенность. Вот теперь, кажется, Вы знаете о строках все. Настала пора переходить к более интересной части статьи — как с этим всем жить? Преобразование строк из одного типа в другойЗдесь, все как обычно, и просто и сложно. Преобразование между «настоящими» строковыми типами String[n], ShortString, и AnsiString выполняются легко, и прозрачно. Никаких явных действий делать не надо, Delphi все сделает за Вас. Надо лишь понимать, что в маленькое большое не влезает. Например: В результате выполнения этого кода, в переменной s3 окажется строка ‘abc’, а не ‘abcdef’. С преобразованием из pChar в String[n], ShortString, и AnsiString, тоже всё очень не плохо. Просто присваивайте, и все будет нормально. Сложности начинаются тогда, когда мы начинаем преобразовывать «настоящие» строковые типы в pChar. Непосредственное присваивание переменным типа pChar значений строк не допускается компилятором. На оператор p := s где p имеет тип pChar, а s :AnsiString, компилятор выдаст сообщение: «Incompatible types: ‘String’ and ‘PChar'» — несовместимые типы ‘String’ и ‘PChar’. Чтобы избежать такой ошибки, надо применять явное приведение типа: p := pChar(s). Так рекомендуют разработчики Delphi. В общем, они правы. Но, если вспомнить, как хранятся динамические строки — с нулем в конце, как и pChar. А еще и то, что к AnsiString применимо преобразование в тип Pointer. Станет очевидным, что всего, возможно целых три способа преобразования строки в pChar: Все они, синтаксически правильны. И кажется, что все три указателя (p1, p2 и p3) будут в результате иметь одно и то же значение. Но это не так. Всё зависит от того, что находится в s. Если быть более точным, равно ли значение s пустой строке, или нет: Чтобы Вы понимали причину такого явления, я опишу, как Delphi выполняет каждое из этих преобразований. В начале напомню, что переменные AnsiString представляющие пустые строки, реально имеют значение Nil. Так вот: Для выполнения преобразования pChar(s), компилятор генерит вызов специальной внутренней функции @LstrToPChar. Эта функция проверяет — если строковая переменная имеет значение Nil, то вместо него, она возвращает указатель на реально размещенную в памяти пустую строку. Т.е. pChar(s) никогда не вернет указатель равный Nil. Тут все просто, такое преобразование просто возвращает содержимое строковой переменной. Т.е. если она при пустой строке содержит Nil, то и результатом преобразования будет Nil. Если же строка не пуста, то результатом будет адрес экземпляра строки. Здесь, все совсем по другому. Перед выполнением такого преобразования, компилятор вставляет код, обеспечивающий ситуацию, когда указатель, хранящийся в s, будет единственным указателем на экземпляр строки в памяти. В нашем примере, если строка не пуста, то будет создана копия исходной строки. Вот ее-то адрес и будет возвращен как результат такого преобразования. Но, если строка пуста, то результатом будет Nil, как и во втором случае. Теперь, интересно отметить, что если в приведенном примере, преобразование p3 := @(s[1]) выполнить первым, то при не пустой строке в s, все указатели (p1, p2, и p3), будут равны. И содержать они будут адрес «персонального» экземпляра строки. Вот, теперь, зная как выполняются те или иные преобразования, Вы сможете всегда выбрать подходящий способ. Для тех, кто ещё не «проникся» до конца этой проблемой, приведу пример. В нем, преобразование, рекомендуемое разработчиками, приводит к «странному» поведению программы: вызывает ошибку доступа к памяти при выполнении строки, помеченной 1. Вот и приходится применять эту функцию. Здесь, поскольку параметр передаётся по значению, при вызове будет создана локальная копия переменной (указателя) Msg. Об этом я ещё расскажу ниже. Эта переменная, при завершении процедуры будет уничтожаться, что приведёт к освобождению «персональной» копии экземпляра переданной и преобразованной строки. Функции этой группы используются для сравнения строк. Результатом будет одно из значений: >0 если S1 > S2 Если же тебе достаточно и 255 символов, то используй ShortString, или String[n]. Есть еще одно, на мой взгляд, замечание. Если Вы обратили внимание на тип переменной Len в моем примере, то возможно у Вас возник вопрос: А почему LongInt, а не Integer? Жаль если у Вас вопрос не возник — либо вы все знаете, либо ничего :). Для остальных поясню: дело в том, что тип LongInt фундаментальный тип, размер которого (4 байта) не будет меняться в последующих версиях Delphi. А тип Integer, это универсальный тип, размерность которого может меняться от версии к версии. Например, для 64-разрядных компьютеров он наверняка «вырастет» до 8-ми байт (64 бита). Лично мне, хочется, что бы файлы данных записанные моей старой версией программы могли быть нормально прочитаны более поздними версиями, возможно скомпилированными уже под 64-разрядной OS. Использование строк в записяхПроблема возникает тогда, когда одно поле (или несколько полей) имеют тип динамической строки. В этом случае, часто возникает проблема схожая с проблемой записи динамической строки в файл — не все данные лежат в записи, динамические строки представлены в ней лишь указателями. Решается проблема также как и с записью строк в файл. Жаль только что тогда нельзя будет оперировать (записать/прочитать) целиком всей записью. Строки придется обрабатывать особо. Можно сделать, например, так: Обратите внимание на то, что перед записью в поток я делаю так, что бы в поле f3 попал указатель Nil. Если этого не сделать, то в поток попадет адрес текущего экземпляра динамической строки. При чтении, он будет прочитан в поле f3. Т.е. поле f3 станет указывать на какое-то место в памяти. При выполнении SetLength, поскольку Delphi сочтет что текущее значение f3 лежит по указанному адресу, будет попытка интерпретировать лежащую там информацию как динамическую строку. Если же в поток записать Nil, то SetLength, никуда лезть не будет — экземпляра-то нет. Использование строк в качестве параметров и результатов функций размещенных в DLL.Многие, наверное, пытались хоть раз написать собственную Dll. Если при этом Вы использовали соответствующего мастера Delphi, то наверняка видели комментарий который он вставляет в начало файла библиотеки: Общий смысл этого эпоса в том, что если Ваша Dll экспортирует хотя бы одну процедуру или функцию с типом параметра соответствующим любой динамической строке (AnsiString например), или функцию, возвращающую результат такого типа. Вы должны обязательно и в Dll, и в использующей ее программе, первым модулем в списке импорта (uses) указать модуль ShareMem. И как следствие, поставлять со своей программой и Dll еще одну стандартную библиотеку BORLNDMM.DLL. Вы не задумывались над вопросами: «Зачем все эти сложности?»; «Что будет если этого не сделать?» и «Можно ли этого избежать?»; «Если да, то как?» Если не задумывались, то самое время сделать это. Попробуем разобраться что будет происходить с экземплярами динамических строк в следующем примере: Сначала, при выполнении процедуры X, функция IntToStr(100) создаст экземпляр динамической строки ‘100’, и ее адрес будет помещен в переменную Str. Затем, адрес этой переменной будет передан процедуре Y. В ней, при выполнении оператора s := s+’$’, будет создан экземпляр новый строки ‘100$’, Экземпляр старой строки ‘100’ станет не нужным и память, выделенная для него при создании, будет освобождена. Кроме того, при завершении процедуры X, будет освобождена и память, выделенная для строки ‘100$’, так как перестанет существовать единственная ссылка на нее — переменная Str. Всё вроде бы хорошо. Но до тех пор, пока обе процедуры располагаются в одном исполняемом модуле (EXE-файле). Если например поместить процедуру Y в Dll, а процедуру X оставить в EXE, то будет беда. Дело в том, что выделением и освобождением памяти для экземпляров динамических строк занимается внутренний менеджер памяти Delphi-приложения. Использовать стандартный менеджер Windows очень накладно. Он слишком универсален, и потому медленный, а строки очень часто требуют перераспределения памяти. Вот разработчики Delphi и создали свой. Он ведет списки распределенной и свободной памяти своего приложения. Так вот, вся беда в том, что Dll будет использоваться свой менеджер памяти, а EXE свой. Друг о друге они ничего не знают. Поэтому, попытка освобождения блока памяти выделенного не своим менеджером приведёт к серьезному нарушению в его работе. Причем, это нарушение может проявиться далеко не сразу, и довольно необычным образом. В нашем случае, память под строку ‘100’ будет выделена менеджером EXE-файла, а освобождаться она будет менеджером DLL. То же произойдет и с памятью под строку ‘100$’, только наоборот. Для преодоления этой проблемы, разработчики Delphi создали библиотеку BORLNDMM.DLL. Она включает в себя еще один менеджер памяти :). Использование же модуля ShareMem, приводит к тому, что он заменяет встроенный в EXE (DLL) менеджер памяти на менеджер расположенный в BORLNDMM.DLL. Т.е., теперь и EXE-файл и DLL, будут использовать один, общий менеджер памяти. Здесь важно отметить то, что если какой-либо из программных модулей (EXE или DLL) не будут иметь в списке импорта модуля ShareMem, то вся работа пойдет насмарку. Опять будут работать несколько менеджеров памяти. Опять будет бардак. Можно обойтись и без внешнего менеджера памяти (BORLNDMM.DLL). Но для этого, надо например заменить встроенный в DLL менеджер памяти, на менеджер, встроенный в EXE. Такое возможно. Есть даже соответствующая реализация от Emil M. Santos, называемая FastShareMem. Найти ее можно на сайте http://www.codexterity.com. Она тоже требует обязательного указания ее модуля FastShareMem в списках используемых модулей EXE и DLL. Но, она по крайней мере не требует таскать за собой ни каких дополнительных DLL’лек. Ну вот, наконец-то и все. Теперь, Вы знаете о строках почти столько же как я :). Конечно, этим тема не исчерпывается. Например, я ничего не рассказал о мультибайтовых строках (MBCS) используемых для мультиязыковых приложений. Может и еще что-то забыл рассказать. Но, не расстраивайтесь. Я свои знания получал, изучая книги, тексты своих и чужих программ, код сгенерированный компилятором, и т.п. Т.е., все из открытых источников. Значит это все доступно и Вам. Главное, чтобы Вы были любознательными, и почаще задавали себе вопросы «Как?», «Почему?», «Зачем?». Тогда во всем сможете разобраться и сами. Приглашаем авторов в рассылку! С уважением, Классификация типов данных в Delphi. Типы с плавающей точкой (Double, Single, Real, Extended)Типы бывают: 1)Простые/Порядковые (целый, логический, символьный, перечисляемый, диапазон (интервальный тип)); 2)Вещественный; 3)Структурированные(массивы, записи, файлы, классы, интерфейсы); 4)Строки; 5)Указатели; 6)Вариант; 7)Процедурный тип. Типы с плавающей точкой:
S-e-m Здесь m – знаковый разряд числа; e – экспоненциальная часть (содержит двоичный порядок); m – мантисса числа. Мантисса m имеет длину от 23 (для Single) до 63 (для Extended) двоичных разрядов, что и обеспечивает точность 7-8 для Single и 19-20 для Extended десятичных цифр. Десятичная точка(запятая) подразумевается перед левым (старшим) разрядом мантиссы, но при действиях с числом она сдвигается влево и вправо в соответствии с двоичным порядком числа, хранящимся в экспоненциальной части, поэтому действия над вещественными числами называют арифметикой с плавающей точкой(запятой). К порядковым типам относятся целые типы, логический и символьный типы, а так же перечисления и тип-диапазон(пользовательский тип). К любому из них применима функция ORD(X) , которая возвращает порядковый номер значения выражения X. Для целых типов ORD(X) возвращает само значение X. Применение к логическому, символьному и к перечислениям дает «+» целое число в диапазоне 0-1(лог. тип), 0-255 (символьный), 0-65535 (перечисление). У типа-диапазон результат применения ord(x) зависит от свойств базового порядкового типа. SUCC(X)– возвращает следующее значение порядкового типа( ord(succ(x)) = ord(x)+1).
К типам применимы следующие функции : Abs(x)–возвращает модуль X Chr(x)–возвращает символ по его коду Dec(x)–уменьшает значение на 1 Inc(x)–увеличивает значение на 1 Mod–дробная часть деления Sqr(x)–возвращает квадрат X А так же операции *,/,+,—. 12.Порядковые типы. Символьный тип. Таблица символов. Тип ANSIChar представляет собой так называемые Ansi-символы. Это символы, которые используются в операционных системах семейства Windows(размером 1 байт). Тип WideChar предназначен для хранения так называемых Unicode-символов, которые в отличие от Ansi-симвояов занимают два байта. Это позволяет кодировать символы числами от 0 до 65535 и используется для представления различных азиатских алфавитов. Первые 256 символов в стандарте Unicode совпадают с символами Аnsi.Тип Char в Delphi 7 эквивалентен типу AnsiChar и обеспечивает наибольшую производительность. Для отображения множества символов в подмножество натуральных чисел и обратно имеются следующие две стандартные функции: ord(c) — дает порядковый номер символа с; 14.Порядковые типы. Перечисляемый тип.(пользовательский тип) Описание переменных : var snd:TSound; 15.Тип массив(статический) : описание, ввод, вывод. Форматный вывод.
16.Тип запись : описание, ввод, вывод, Оператор With. Запись с вариантами.
S2:=[‘2’,’3’,’1’]; 18.Текстовый файл : описание файловой переменной, основные операции. Использование параметров программы для передачи программе имен файлов. Основные операторы для работы с текстовыми файлами: Операторы ввода-вывода: Все параметры трактуются как отдельные строки (string). Параметры пользователя нумеруются, начиная с единицы. В нулевом параметре ParamStr(0) ОС передает программе полное имя запускаемого приложения (например, D:\Гречкина\Project1.exe). Этот (нулевой) параметр не входит в общее число параметров, которое можно узнать с помощью функции ParamCount: function ParamCount: word. procedure имя процедуры (формальные параметры); раздел описаний процедурыbegin исполняемая часть процедурыend; … function имя функции (формальные параметры):тип результата; раздел описаний функции begin Формальный параметр-значение обрабатывается, как локальная по отношению к процедуре или функции переменная, за исключением того, что он получает свое начальное значение из соответствующего фактического параметра при активизации процедуры или функции. Изменения, которые претерпевает формальный параметр-значение, не влияют на значение фактического параметра. implementation begin end. При восходящем подходе программа собирается и тестируется снизу вверх. Только модули самого нижнего уровня (модули, не вызывающие других модулей) тестируются независимо, автономно. После того как тестирование этих модулей завершено, вызов их должен быть так же надежен, как вызов встроенной функции языка или оператор присваивания. Затем тестируются модули, непосредственно вызывающие уже проверенные. Эти модули более высокого уровня тестируются не автономно, а вместе с уже проверенными модулями более низкого уровня. Процесс повторяется до тех пор, пока не будет достигнута вершина. Здесь завершаются и тестирование модулей, и тестирование сопряжений программы. Для каждого модуля необходимо написать небольшую ведущую программу. Delphi in a Nutshell by Ray LischnerStay ahead with the world’s most comprehensive technology and business learning platform.With Safari, you learn the way you learn best. Get unlimited access to v > Start Free TrialNo credit card required SyntaxDescriptionThe Comp type is a 64-bit signed integer type that uses the floating-point processor. The Comp type exists only for backward compatibility. New programs should use Int64 instead. The Int64 type is a true integer type and allows bitwise and shift operations, supports the full range of the 64-bit type, and is not dependent on the floating-point control word. Tips and TricksTo use the full 64-bit precision of the Comp type, the floating-point control word must be set to extended precision. Some Microsoft and other DLLs change the floating-point control word to double or single precision, thereby reducing the Comp type to 53 or fewer bits. Delphi’s I/O and the formatting routines in the SysUtils unit do not support the full range of the Comp type. Values near the limits of the Comp type are printed with less precision than is actually stored in the Comp variable. Most applications will not encounter this limitation. Типы данных в DELPHIС помощью типов данных программист указывает компилятору, как хранить информацию в программе. При объявлении переменной необходимо указать ее тип. Одни типы уже определены в языке, другие программисту приходится задавать самому. В ранних языках программирования допускалось ограниченное число типов данных, и Pascal оказался одним из первых языков, допускающих определение в программе новых типов. Типы данных, определяемые пользователем, обычно задаются в разделе определения типов программы или модуля (unit), однако это можно делать и внутри процедур или функции. Объявления типов действуют в пределах того блока, в котором они размещены. Вне этого блока ссылаться на такие типы нельзя. Внутри же они заменяют все внешние типы с тем же именем. Объявленные типы данных можно применять в любом месте области их видимости; запрещена только ссылка определяемого типа на самого себя (тут, однако, есть одно исключение, касающееся указателей). Объявления типов в Pascal являются для компилятора чем-то вроде схем, которые он должен запомнить на случай, если вдруг встретит в программе ссылки на тот или иной тип. Само по себе объявление типа не вносит в программу никаких изменений. Что же касается объявлений var, то они задают компилятору некоторые действия, связанные с ранее объявленными типами. Тип переменной ограничивает как ее значения, так и операции, которые можно выполнять с этими значениями. Определения типов и переменных могут размещаться в нескольких местах компонентов программы. Выглядят же они следующим образом. type Синтаксис Object Pascal позволяет одновременно конструировать исключительно сложные типы и определение переменных. Однако определение типов в разделах type тех или иных блоков дает возможность использовать эти типы в разных частях программы. Новые типы определяются из типов следующих категории.
Обычно идентификаторы типов используются только при определении новых типов или объявлении переменных. Есть, однако, несколько функций, в которых имя типа может использоваться как часть выполняемого оператора. Например, функция SizeOf (Т) возвращает количество байтов, занимаемых переменной Т. Функция SizeOf очень важна для написания эффективных программ. Многие из определенных в Object Pascal типов имеют очень сложную структуру и могут занимать в памяти довольно много места. При этом элементы таких типов созданы скорее для представления значений в некотором логическом порядке, а не для того, чтобы занимать место в памяти. Функция SizeOf избавляет программиста от необходимости вычислять объем данных в подобных случаях. Простые типы данных Порядковые типы Любой реально существующий тип данных, каким бы сложным он ни казался на первый взгляд, представляет собой простые составляющие, которыми процессор может манипулировать. В Object Pascal эти простые типы данных разбиты на две группы: порядковые, представляющие данные разных объемов, которыми процессор может легко манипулировать, и действительные, представляющие приближенно математические действительные числа. Разделение типов на порядковые и действительные несколько условно. Точно так же простые данные можно было бы разделить на числа и не числа. Однако в языке Object Pascal порядковые и действительные данные трактуются по-разному, и такое разделение даже полезно. Порядковые типы Из простых типов данных порядковые — самые простые. В этих типах информация представляется в виде отдельных элементов. Связь между отдельными элементами и их представлением в памяти определяет естественные отношения порядка между этими элементами. Отсюда и название порядковые. В Object Pascal определены три группы порядковых типов и два типа, определяемых пользователем. Группы — это целые, символьные и булевы типы. Порядковые типы, задаваемые пользователем, — это перечисления и поддиапазоны. Все значения любого порядкового типа образуют упорядоченную последовательность, и значение переменной порядкового типа определяется его местом в этой последовательности. За исключением переменных целых типов, значения которых могут быть как положительными, так и отрицательными, первый элемент любого порядкового типа имеет номер 0, второй элемент — номер 1 и т.д. Порядковый номер целого значения равен самому значению. Отношение порядка определяет общие для данных всех порядковых типов операции. Некоторые стандартные функции такого вида встроены в Object Pascal. Они представлены в табл. 1.1. Для всех порядковых типов в Object Pascal существует операция задания типа для преобразования целых значений в значения соответствующих порядковых типов. Если Т — имя порядкового типа, а Х — целое выражение, то Т (X) воз-вращает значение Т с порядковым номером X. Таблица 1.1. Операции над порядковыми типами Минимальное значение порядкового типа Т Максимальное значение порядкового типа Т Порядковый номер значения выражения порядкового типа. Для целого выражения — просто его значение. Для остальных порядковых типов Ord возвращает физическое представление результата выражения, трактуемое как целое число. Возвращаемое значение всегда принадлежит одному из целых типов Предыдущее по порядку значение. Для целых выражений эквивалентно Х-1 Следующее по порядку значение. Для целых выражений эквивалентно Х+1 Уменьшает значение переменной на 1. Эквивалентно V := Pred(V) Увеличивает значение переменной на 1. Эквивалентно V := Succ(V) Целые типы В переменных целых типов информация представляется в виде целых чисел, т.е. чисел не имеющих дробной части. Определенные в Object Pascal целые типы подразделяются на физические (фундаментальные) и логические (общие). При программировании удобнее использовать логические целые типы, которые задают объем переменных в зависимости от типа микропроцессора и операционной среды таким образом, чтобы достигалась максимальная эффективность. Физические целые типы следует применять лишь в тех случаях, когда в первую очередь важны именно диапазон значений и физический объем переменной. В Object Pascal определены следующие целые типы. Обратите внимание, что один из этих целых типов назван именно целым (integer). Это может иногда приводить к путанице, но мы легко сможем ее избежать, применяя термин целый к. группе типов, a integer — к конкретному типу, определяемому в программе этим ключевым словом. Переменные физических целых типов имеют разные диапазоны значений в зависимости от того, сколько байтов памяти они занимают (что равно значению, возвращаемому функцией SizeOf для данного типа). Диапазоны значений для всех физических типов перечислены в табл. 1.2. Таблица 1.2. Физические целые типы 8 бит, со знаком 16 бит, со знаком -2 147 483 648-2 147 483 647 32 бит, со знаком 8 бит, без знака 16 бит, без знака Диапазоны значений и форматы физических целых типов не зависят от микропроцессора и операционной системы, в которых выполняется программа. Они не меняются (или, по крайней мере, не должны меняться) с изменением реализации или версии Object Pascal. Диапазоны значений логических целых типов (Integer и Cardinal) определяются совершенно иным образом. Как видно из табл. 1.3, они никак не связаны с диапазонами соответствующих физических типов. Обратите внимание, что в Delphi по умолчанию задано 32-разрядное представление. Таблица 1.3. Логические целые типы 16 бит, со знаком (SmalIInt) -2 147 483 648-2 147 483 647 32 бит, со знаком (Longint) 16 бит, без знака (Word) 32 бит, без знака (Longint) Над целыми данными выполняются все операции, определенные для порядковых типов, но с ними все же удобнее работать как с числами, а не с «нечисленными порядковыми типами». Как и «живые» числа, данные целых типов можно складывать (+), вычитать (-) и умножать (*). Однако некоторые операции и функции, применяемые к данным целых типов, имеют несколько иной смысл. Возвращает абсолютное целое значение Х Возвращает целую часть частного деления Х на Y Возвращает остаток частного деления Х на Y Возвращает булево True (истина), если Х — нечетное целое, и False (ложь) — в противном случае Возвращает целый квадрат Х (т.е. Х*Х) Символьные типы Смысл символьных данных очевиден, когда они выводятся на экран или принтер. Тем не менее, определение символьного типа может зависеть от того, что подразумевать под словом символ. Обычно символьные типы данных задают схему взаимодействия между участками памяти разного объема и некоторым стандартным методом кодирования/декодирования для обмена символьной информацией. В классическом языке Pascal не задано никакой схемы, и в конкретных реализациях применялось то, что на том же компьютере мог использовать каждый. В реализациях языка Pascal для первых микропроцессоров была применена 7-битовая схема, названная ASCII (American Standard Code for Information Interchange — Американский стандартный код для обмена информацией). Эта схема и поныне широко распространена, но информация хранится, как правило, в 8-битовых участках памяти. Дополнительный бит удваивает число возможных представлений символов, но реализации расширенного набора символов ASCII часто бывают далеки от стандарта. В данной версии Delphi определен набор 8-битовых символов, известный как расширенный (extended) ANSI (American National Standards Institute — Американский национальный институт стандартов). Как бы то ни было, символьную схему приходится воспринимать так, как ее воспринимает операционная система. Для оконных операционных систем фирмы Microsoft это схема ANSI, включающая ограниченное число предназначенных для вывода международных знаков. В стремлении же применить более обширный набор международных знаков весь компьютерный мир переходит к 16-битовой схеме, именуемой UNICODE, в которой первые 256 знаков совпадают с символами, определенными в схеме ANSI. Для совместимости со всеми этими представлениями в Object Pascal определены два физических символьных типа и один логический. Физические типы перечислены ниже. Однобайтовые символы, упорядоченные в соответствии с расширенным набором символов ANSI Символы объемом в слово, упорядоченные в соответствии с международным набором символов UNICODE. Первые 256 символов совпадают с символами ANSI Символьные типы объемом в двойное слово (32 бит) отсутствуют. Логический символьный тип именуется char. В классическом языке Pascal char- единственный символьный тип. В Delphi char всегда соответствует физическому типу данных AnsiChar. У американских программистов ассоциация символа с однобайтовой ячейкой памяти укоренилась за долгие годы настолько, что им зачастую просто не приходит в голову, что можно использовать другие схемы кодирования. Однако дискуссии по интернационализации программ в Internet и World Wide Web могут существенно изменить их отношение к проблеме объема символьных данных. Применяя логический тип char, следует делать реализации для других микропроцессоров и операционных систем, в которых char может определяться как WideChar. При написании программ, которые могут обрабатывать строки любого размера, для указания этого размера рекомендуется применять функцию SizeOf, не задавая ее жестко постоянной. Функция Ord (С), где С — любая переменная символьного типа, возвращает целое значение, которым символ С представлен в памяти. Преобразует целую переменную в переменную типа char с тем же порядковым номером. В Delphi это эквивалентно заданию типа Char (X) Преобразует строчную букву в прописную Булевы типы На ранней стадии обучения программисты осваивают понятие бита, два состояния которого можно использовать для записи информации о чем-либо, представляющем собой одно из двух. Бит может обозначать 0 или 1, ДА или НЕТ, ВКЛЮЧЕНО или ВЫКЛЮЧЕНО, ВЕРХ или НИЗ, СТОЯТЬ или ИДТИ. В Object Pascal информация о чем-либо, что можно представить как ИСТИНА (True) или ЛОЖЬ (False), хранится в переменных булевых типов. Всего таких типов че-тыре, и они представлены в табл. 1.4. Таблица 1.4. Размеры переменных булевых типов 2 байт (объем Word) 4 байт (объем Longint) По аналогии с целыми и символьными типами, подразделяющимися на физические и логические, естественно предположить, что ByteBool, WordBool и LongBool — физические типы, Boolean — логический. Но в данном случае это не совсем так. Все четыре типа различны. Для Object Pascal предпочтителен тип Boolean, остальные определены для совместимости с другими языками программирования и операционными системами. Переменным типа Boolean можно присваивать только значения True (истина) и False (ложь). Переменные ByteBool, WordBool и LongBool могут принимать и другие порядковые значения, интерпретируемые обычно как False в случае нуля и True — при любом ненулевом значении. Перечислимые типы Type enum type = (first value, value2, value3, last value); Обычно данные перечислимых типов содержат дискретные значения, представляемые не числами, а именами. Тип Boolean- простейший перечислимый тип в Object Pascal. Булевы переменные могут принимать два значения, выражаемые именами True и False, а сам тип определен в Object Pascal так, как будто он объявлен следующим образом: Type Boolean = (False, True); С помощью типа Boolean в Object Pascal выполняются сравнения, большинство же перечислимых типов — это просто списки уникальных имен или идентификаторов, зарезервированных с конкретной целью. Например, можно создать тип MyColor (мой цвет) со значениями myRed, myGreen и myBlue (мой красный, мой зеленый, мой синий). Это делается совсем просто: Type MyColor = (myRed, myGreen, myBlue); В этой строке объявлены четыре новых идентификатора: MyColor, myRed, myGreen и myBlue. идентификатором MyColor обозначен порядковый тип, следовательно, в синтаксисе Object Pascal можно применять этот идентификатор везде, где разрешены перечислимые типы. Остальные три идентификатора- это значения типа MyColor. Подобно символьным и булевым типам перечислимые не являются числами, и использовать их наподобие чисел не имеет смысла. Однако перечислимые типы относятся к порядковым, так что значения любого такого типа упорядочены. Идентификаторам в списке присваиваются в качестве порядковых номеров последовательные числа. Первому имени присваивается порядковый номер 0, второму — 1 и т.д. Поддиапазонные типы Переменные поддиапазонного типа содержат информацию, соответствующую некоторому pаданному диапазону значений исходного типа, представляющего любой порядковый тип, кроме поддиапазонного. Синтаксис определения поддиапазонного типа имеет следующий вид: Type subrange type = low value. high value; Поддиапазонные переменные сохраняют все особенности исходного типа. Единственное отличие состоит в том, что переменной поддиапазонного типа можно присваивать только значения, входящие в заданный поддиапазон. Контроль за соблюдением этого условия задается командой проверки диапазона (range checking). Необходимость явно определять поддиапазонный тип возникает нечасто, но все программисты неявно применяют эту конструкцию при определении массивов. Именно в форме поддиапазонной конструкции задается схема нумерации элементов массива. Действительные типы В переменных действительных типов содержатся числа, состоящие из целой и дробной частей. В Object Pascal определено шесть действительных типов. Все типы могут представлять число 0, однако они различаются пороговым (минимальным положительным) и максимальным значениями, которые могут представлять, а также точностью (количеством значащих цифр) и объемом. Действительные типы описываются в табл. 1.5. Таблица 1.5. Действительные типы. Количество значащих цифр Целые типы представляют целые числа, т.е. числа, дробная часть которых равна нулю. Разница между двумя неодинаковыми целыми числами не может быть меньше единицы. Именно благодаря этому целые числа применяются для обозначения дискретных величин, независимо от того, имеют ли реальные объекты какое-либо отношение к числам. Действительные типы предназначены для представления чисел, которые могут иметь дробную часть, поэтому они полезны для представления величин, которые могут быть довольно близкими, почти непрерывными. Заметьте, именно почти. Несмотря на название действительные, переменные этих типов отличаются от математических действительных чисел. В Object Pascal действительный тип — это подмножество математических действительных чисел, которые можно представить в формате с плавающей запятой и фиксированным числом цифр. Для невнимательных программистов ситуация усугубляется тем, что в стандартных форматах IEEE (Institute of Electrical and Electronic Engi-neers — Институт инженеров- электриков и электронщиков), применяемых в программах Delphi и вообще в большинстве программ для Windows, возможно точное представление только чисел с фиксированным числом бит в дробной части. Удивительно, но такое простое число, как 0,1, записывается в расширенном формате IEEE с некоторой погрешностью, пусть очень небольшой. Из-за этого представление с плавающей запятой оказывается несколько неудобным для программ, в которых сохраняется и выводится фиксированное число десятичных разрядов численных значений. Это относится и к программам, работающим с »живыми» деньгами. Для частичного решения этой проблемы в Object Pascal определены два формата с фиксированной запятой. Тип Comp (computational — вычислительный) содержит только целые числа в диапазоне от -2 63 +1 до 2 63 -1, что примерно соответствует диапазону от -9,2х10 18 до 9,2х10 18 . При программировании операций с американской валютой разработчикам обычно приходится искать естественный способ записи денежных сумм, в котором целая часть числа определяет количество долларов, дробная — центов. Если такие значения записывать в переменные типа Comp, придется представлять их в виде целого числа центов. В этом случае следует умножать значение на 100 для обращения центов в доллары, а затем делить на 100, чтобы снова получить центы. Этих забот можно избежать, если воспользоваться типом Currency. В этом случае задачу выбора масштаба возьмет на себя компилятор. Физически значения Currency записываются в память того же объема, что и Comp, как целые числа, однако компилятор не забывает вовремя разделить значение на 10 000 (не на 100!) для его приведения в соответствие с денежным знаком и умножить на 10 000 перед записью в память. Это обеспечивает абсолютную точность в четыре десятичных знака после запятой. В Delphi есть модуль System, содержащий ряд процедур обработки данных действительных типов. Наиболее распространенные из них перечислены в табл. 1.6. Много полезных процедур содержится также в модулях SysUtils и Math. Таблица 1.6. Функции действительных типов Абсолютная величина х Косинус х (х выражается в радианах, а не в градусах) Экспоненциальная функция от х Дробная часть х Целая часть х. Несмотря на название, возвращает действительное значение (с плавающей запятой), т.е. просто устанавливает нуль в дробной части Натуральный логарифм от х Ближайшее к х целое значение. Возвращает значение целого типа. Условие «ближайшее к х» не работает, если верхнее и нижнее значения оказываются равноудаленными (например, ес-ли дробная часть точно равна 0,5). В этих случаях Delphi перекладывает решение на опера-ционную систему. Обычно процессоры Intel решают эту задачу в соответствии с рекоменда-цией IEEE округлять в сторону ближайшего четного целого числа. Иногда такой подход на-зывают «банкирским округлением» Квадрат х, т.е. X*X Квадратный корень от х Целая часть х. В отличие от Int, возвращающей действительное значение, Trunc возвращает целое В выражениях Delphi поддерживает три физических строковых формата: короткий (ShortString), длинный (LongString) и широкий (WideString). Их можно комбинировать в операторах присваивания и выражениях (все необходимые преобразования Delphi выполняет автоматически). Переменные типов AnsiString и WideString — это динамически распределяемые массивы символов, максимальная длина которых ограничивается только наличием памяти. Разница между ними состоит в том, что в AnsiString знаки записываются в формате char, а в WideString- в формате WideChar. Обычно вполне достаточно одного типа AnsiString, однако при работе с международными наборами символов, такими как UNICODE, удобнее использовать WideString. Тип ShortString-это, по существу, массив Array [0..255] of char. Первый его элемент задает динамическую длину строки, которая может принимать значения от 0 до 255 символов. Символы, составляющие строку, занимают места от 1 до 255. Тип ShortString предназначен, в основном, для обеспечения совместимости с ранними версиями Delphi и Borland Pascal. Логический строковый тип именуется просто String. Отнесение его к типу AnsiString или ShortString задается командой $Н. По умолчанию задается < $Н+>, и String совпадает с AnsiString. Если задать команду <$Н- >, то String будет совпадать с ShortString и иметь максимальную длину, равную 255 символам. Для совместимости с другими языками программирования в Delphi поддерживается класс строк с конечным нулем. Зарезервированных слов или идентификаторов для этого класса не существует. Строки с конечным нулем состоят из ненулевых символов и оканчиваются символом с порядковым номером 0 (#0). В отличие от типов AnsiString, ShortString и WideString, строки с нулевым окончанием не имеют указателя длины. Конец в этих стооках обозначается нулем. Физически строки с нуль-окончанием подобны массивам символов с нумерацией элементов от нуля, наподобие array [ 0 . . X] of char, где Х — некоторое положительное целое, большее нуля, хотя никаких объявлении подобного рода не происходит. Вместо этого определяется переменная-указатель PChar и распределяется необходимый объем памяти. При необходимости строке AnsiString можно присвоить тип PChar. В табл. 1.7 перечислены некоторые процедуры и функции обработки данных строковых типов. Таблица 1.7. Строковые функции Возвращает последовательное соединение строк. Эквивалентна оператору sl+s2+s3 Возвращает подстроку длиной максимум len символов, начинающуюся в позиции pos строки s Delete(s, pos, len) Удаляет максимум len символов из строки s, начиная с позиции pos Insert(sourse, tar-get, pos) Вставляет строку source в строковую переменную target, начиная с позиции pos Возвращает динамическую длину строки. Подобна функциям LEN в Basic и strlen — в C/C++ Возвращает место первого вхождения подстроки substring в строку s. Подобна функциям SUBSTR в Basic и strstr () — в C/C++ Задает новую динамическую длину newlen строковой переменной s Задает содержимое и длину строки Преобразует численное значение х в строковую переменную s Возвращает строку с конкретным числом символов Делает данную строку уникальной со счетом обращений 1 Преобразует строку s в соответствующее численное представление v Записи На элементарном уровне наиболее полезными типами данных являются те, в которых содержится численная и строковая (символьная) информация. Объединив несколько образцов этих элементарных типов, можно создавать более сложные типы данных. Структурные типы данных предоставляют возможность создавать новые типы, расширяя определения уже существующих таким образом, чтобы данные новых типов могли содержать более одного значения. Элементами данных структурных типов можно манипулировать как поодиночке, так и вместе, и эти элементы сами могут быть структурными. Никаких ограничений на подобное вложение одной структуры в другую не существует. Ниже перечислены структурные типы, определенные в Delphi .
Перечисленные типы сами по себе обычно являются не типами, а структурными методами дополнения существующих типов. Записи С помощью зарезервированного слова record (запись) в одном типе можно объединять данные разных типов. Общий синтаксис объявления этого типа выглядит следующим образом: record Данное объявление состоит из фиксированной и вариантной частей. Однако вовсе не обязательно вставлять в одно объявление записи обе эти части. Обычно удобнее работать с каждой из этих частей отдельно. Фиксированные записи В фиксированной части записи определяется одно или несколько независимых полей. Каждому полю обязательно присваивается имя и тип: record Имея доступ к информации в записи, можно обрабатывать всю запись целиком (все поля одновременно) или только отдельное поле. Для обращения к отдельному полю наберите имя записи, точку и идентификатор поля, например Для доступа ко всей записи просто укажите ее имя. Вариантные записи Вариантная часть типа record дает возможность по-разному трактовать область памяти, совместно занимаемую вариантами поля: record Все варианты занимают в памяти одно место. Каждый вариант обозначается некоторой постоянной. При желании можно получать доступ ко всем полям всех вариантов одновременно, однако это может иметь смысл только в наиболее простых случаях, когда точно известно, как именно информация каждого варианта записывается в память. Каждый вариант обозначается минимум одной константой. Все константы должны быть порядковыми и совместимыми по типу с меткой поля. Необязательное поле — это идентификатор дополнительного поля в фиксированной части записи, общий для всех вариантов. Обычно с его помощью определяют, когда к какому варианту обращаться. Массивы Массивы могут быть одно- или многомерными, как в следующем примере. array [ordinal_type] of type_definition; Каждый массив содержит некоторое количество элементов информации одного типа. Для обращения к элементу массива надо указать имя массива и индекс элемента, заключенный в квадратные скобки. Обратите внимание, что число элементов массива в каждом измерении задается порядковым типом (ordinal_type). Для этого можно воспользоваться идентификатором некоторого типа (например, Boolean или AnsiChar), однако на практике обычно явно задается поддиапазон целых. Количество элементов массива равно произведению количеств элементов во всех измерениях. var MyArray: Array [1..10] of Integer; Тогда обращение к его третьему элементу будет выглядеть, как MyArray[З], и выполняться, как к переменной Integer. Множества Зарезервированное слово set (множество) определяет множество не более чем из 256 порядковых значений: Set of ordinal type Минимальный и максимальный порядковые номера исходного типа (на основе которого определяется множественный тип) должны быть в пределах между 0 и 255. Переменная множественного типа содержит (или не содержит) любое значение исходного порядкового типа. Каждое значение из заданного диапазона может принадлежать или не принадлежать множеству. Рассмотрим следующий пример. Type CharSet = set of AnsiChar; // Тип множества символов. ANSI. Переменная set может содержать все элементы множества или не содержать ни одного. При присвоении значения переменной множественного типа элементы множества (порядковые значения) указываются в квадратных скобках: MyAlphaSet := [‘А’, ‘Е’, ‘Г, ‘О’, ‘U’, ‘Y’]; // Все прописные гласные. Пустые квадратные скобки задают пустое множество, не содержащее ни одного элемента. Это относится ко всем множественными типам. Файловый тип Тип file предназначен для доступа к линейной последовательности элементов, которые могут представлять данные любого типа, кроме содержащих типы file и class. Объявление файлового типа подобно объявлению массива, только без указания числа элементов. file of Typel // Файл определенного типа, содержащий Механизм ввода-вывода информации как никакой другой аспект программирования зависит от языка и реализации. В большинстве случаев предполагается, что программисту незачем вникать во внутреннюю структуру переменных, управляющих вводом-выводом, и при передаче информации следует полностью полагаться на предназначенные для этого процедуры. Их реализация должна оставаться чем-то наподобие черной магии. В Basic файлы обозначаются числовыми значениями — дескрипторами. В C/C++ программисты манипулируют указателями на структуру FILE. И только в Delphi файловая структура — это переменная. Переменная указательного типа содержит значение, указывающее на переменную обычного типа — адрес этой переменной (табл. 1.8). pointer // Указатель без типа. Если исходный тип (тип переменной, на которую должен ссылаться указатель) еще не объявлен, его надо объявить в том же разделе объявления типов, что и тип указателя. Только исходный тип указателей может совпадать с собственно типом. Таблица 1.8. Средства работы с указателями Распределяет новый участок динамической памяти и записывает его адрес в переменную указательного типа Направляет переменную-указатель на область памяти, содержащую любую существующую переменную, процедуру или функцию, включая переменные, имеющие идентификаторы Создает новую динамическую переменную заданного объема и записывает ее адрес в переменную указательного типа Указатели и адресные функции Информация, содержащаяся в переменной указательного типа, — это адрес некоторого участка в машинной памяти. Эти значения задаются во время работы программы и могут меняться от одного запуска к другому. Следующие функции обеспечивают доступ к адресной информации в программе и тестирование переменных-указателей. Возвращает адрес указанного объекта Проверяет, равно ли значение процедурной функции Nil Преобразует адрес в указатель type Однако необъявленный тип необходимо объявить ниже в том же блоке объявления типов. Определенный в Object Pascal тип Pointer- это указатель без типа. Обратиться к переменной через такой указатель невозможно (к переменной типа Pointer нельзя дописывать символ «^»). Однако можно задать ей другой указательный тип. По значениям переменных тип Pointer совместим с остальными указательными типами. Тип Variant Указатели удобны для записи информации заданного типа и обращения к переменным. Однако записывать адреса процедур и функций довольно опасно. Программистам, работавшим с ранней версией Turbo Pascal, приходилось основательно изучать способы размещения процедур и функций в памяти и обращения к ним. Процедурные типы существенно упрощают эту проблему, позволяя трактовать процедуры и функции как значения, которые можно присваивать переменным и передавать в качестве параметров. Объявление процедурного типа подобно объявлению заголовка процедуры или функции. Единственная разница состоит в том, что опускается имя. следующее обычно после ключевых слов procedure и function. Вне типа Class в Object Pascal разрешены только глобальные процедурные переменные. Это означает, что процедурной переменной не может быть присвоена процедура или функция, объявленная внутри другой процедуры или функции. Кроме того, в Delphi можно применять данные процедурных типов, представляющих собой методы. При выполнении программы можно обращаться к определенным методам определенных переменных-объектов. Использование методов в качестве данных процедурных типов позволяет модифицировать поведение переменной-объекта некоторого класса, не объявляя нового класса с новыми методами. В Delphi указатели процедурного типа на методы применяются для сопоставления событий с образцами текста программы. С точки зрения синтаксиса, единственное отличие процедурного типа для метода от обычного процедурного типа состоит в фразе of object, следующей за прототипом процедуры или функции в случае метода. Особым образом применяется в процедурных методах указательное значение Nil. Это единственное указательное значение, которое можно присвоить процедурной переменной. После присвоения такого значения процедурная переменная становится неопределенной. Состояние определенности можно проверить с помощью функции Assigned. Глобальные процедурные типы и процедурные типы для методов взаимно несовместимы. Нельзя присваивать значение одного типа переменной другого. Физически процедурные типы в Delphi совпадают с указательными, однако они различаются синтаксически, поэтому нельзя обращаться к функции или процедуре через указатель. Тем не менее при обращении к процедурной переменной задействуется именно значение указательного типа. В C/C++ переменная может иметь тип указателя на функцию. В версиях языка С до введения стандарта ANSI для обращения к соответствующей функции приходилось явно адресовать указатель. В версиях С, со-ответствующих стандартам ANSI, возможны как явная, так и неявная адресации указателей. Delphi удобна для тех, кому близок стиль ANSI. Тип Variant Тип Variant предназначен для представления значений, которые могут динамически изменять свой тип. Если любой другой тип переменной зафиксирован, то в переменные типа Variant можно вносить переменные разных типов. Шире всего тип Variant применяется в случаях, когда фактический тип данных изменяется или неизвестен в момент компиляции. Вариантные значения При рассмотрении типа Record мы ознакомились с вариантной частью записи, где в одном фрагменте памяти можно хранить информацию нескольких типов. Такой метод недостаточно нагляден. Много ли пользы от того, чтобы найти в памяти действительное значение с фиксированной запятой и интерпретировать его, как целое! Тип Variant (не имеющий ничего общего с вариантной частью записи) более «проворен» и полезен в управлении данными разных типов. Переменным типа Variant можно присваивать любые значения любых целых, действительных, строковых и булевых типов. Для совместимости с другими языками программирования предусмотрена также возможность присвоения этим переменным значений даты/времени и объектов OLE Automation. Кроме того, вариантные переменные могут содержать массивы переменной длины и размерности с элементами указанных типов. Все целые, действительные, строковые, символьные и булевы типы совместимы с типом Variant в отношении операции присваивания. Вариантные переменные можно сочетать в выражениях с целыми, действительными, строковыми, символьными и булевыми; при этом все необходимые преобразования Delphi выполняет автоматически. Можно произвольно задавать для выражении тип Variant в форме Variant (X). В Object Pascal определены два особых значения Variant. Значение Unassigned применяется для указания, что вариантной переменной пока не присвоено значение какого бы то ни было типа. Значение Null указывает на наличие в переменной данных неизвестного типа или потерю данных. Разницу между этими двумя значениями трудно уловить. Значение Unassigned присваивается вариантным переменным автоматически при их создании, независимо от того, локальная это переменная или глобальная, и является ли она частью другой, структурной, переменной, такой как запись или массив. Unassigned означает, что к данной вариантной переменной еще не обращались. Null же означает, что к вариантной переменной обращались, но не ввели в нее никакой информации. Таким образом, Null указывает, что значение вариантной переменной недействительно или отсутствует. Вариантные переменные предоставляют широкие возможности формирования выражений с переменными разных типов. Однако за это приходится платить большим, по сравнению с жестко задаваемыми типами, расходом памяти. К тому же на выполнение операций с вариантными переменными требуется больше времени. Интересна проблема использования вариантной переменной как массива. Элементы этого массива должны быть одного типа. На первый взгляд, это вполне естественное условие. Однако элементам массива можно присвоить и тип Variant! Тогда каждый элемент сможет содержать информацию разных типов, в том числе массив Variant. Как правило, вариантные массивы создаются с помощью процедуры VarArrayCreate. Для передачи двоичной информации между контроллерами автоматизации OLE и серверами обычно применяются вариантные массивы с элементами varByte. Вариантные массивы типа varByte не могут подвергаться никаким преобразованиям. Нельзя также переформатировать содержащуюся в них двоичную информацию. Эффективный доступ к ним осуществляется с помощью процедур VarArrayLock и VarArrayUnlock. Элементы вариантного массива не могут иметь тип varString. Для создания вариантных массивов со строковыми элементами следует выбрать тип varOleStr. Процедуры обработки вариантных массивов В табл. 1.9 перечислены стандартные процедуры и функции обработки вариантных массивов, определенные в модуле System. Таблица 1.9. Процедуры и функции обработки вариантных массивов Borland Delphi 4.0 для начинающих — Типы данных — Простые типы данныхЛюбой реально существующий тип данных, каким бы сложным он ни казался на первый взгляд, представляет собой простые составляющие, которыми процессор может манипулировать. В Object Pascal эти простые типы данных разбиты на две группы: порядковые, представляющие данные разных объемов, которыми процессор может легко манипулировать, и действительные, представляющие приближенно математические действительные числа. Разделение типов на порядковые и действительные несколько условно. Точно так же простые данные можно было бы разделить на числа и не числа. Однако в языке Object Pascal порядковые и действительные данные трактуются по-разному, и такое разделение даже полезно. Порядковые типыИз простых типов данных порядковые — самые простые. В этих типах информация представляется в виде отдельных элементов. Связь между отдельными элементами и их представлением в памяти определяет естественные отношения порядка между этими элементами. Отсюда и название порядковые. В Object Pascal определены три группы порядковых типов и два типа, определяемых пользователем. Группы — это целые, символьныеи булевы типы. Порядковые типы, задаваемые пользователем, — это перечисления и поддиапазоны. Все значения любого порядкового типа образуют упорядоченную последовательность, и значение переменной порядкового типа определяется его местом в этой последовательности. За исключением переменных целых типов, значения которых могут быть как положительными, так и отрицательными, первый элемент любого порядкового типа имеет номер 0, второй элемент — номер 1 и т.д. Порядковый номер целого значения равен самому значению. Отношение порядка определяет общие для данных всех порядковых типов операции. Некоторые стандартные функции такого вида встроены в Object Pascal. Они представлены в табл. 1.1. Для всех порядковых типов в Object Pascal существует операция задания типа для преобразования целых значений в значения соответствующих порядковых типов. Если Т — имя порядкового типа, а Х — целое выражение, то Т (X) воз-вращает значение Т с порядковым номером X. Совет:Программисты, работающие на С и C++, для приращения или уменьшения значений переменных привыкли заметку использовать операторы «++» и «—«, возвращающие следующее и предыдущее значения. Программисты Delphi всегда разбивают эти операции на более простые составляющие с помощью функций Pred, Succ. Dec и Inc.
Целые типыВ переменных целых типов информация представляется в виде целых чисел, т.е. чисел не имеющих дробной части. Определенные в Object Pascal целые типы подразделяются на физические (фундаментальные) и логические (общие). При программировании удобнее использовать логические целые типы, которые задают объем переменных в зависимости от типа микропроцессора и операционной среды таким образом, чтобы достигалась максимальная эффективность. Физические целые типы следует применять лишь в тех случаях, когда в первую очередь важны именно диапазон значений и физический объем переменной. В Object Pascal определены следующие целые типы. Обратите внимание, что один из этих целых типов назван именно целым (integer). Это может иногда приводить к путанице, но мы легко сможем ее избежать, применяя термин целый к. группе типов, a integer — к конкретному типу, определяемому в программе этим ключевым словом. Переменные физических целых типов имеют разные диапазоны значений в зависимости от того, сколько байтов памяти они занимают (что равно значению, возвращаемому функцией SizeOf для данного типа). Диапазоны значений для всех физических типов перечислены в табл. 1.2. Таблица 1.2. — Физические целые типы
Диапазоны значений и форматы физических целых типов не зависят от микропроцессора и операционной системы, в которых выполняется программа. Они не меняются (или, по крайней мере, не должны меняться) с изменением реализации или версии Object Pascal. Диапазоны значений логических целых типов (Integer и Cardinal) определяются совершенно иным образом. Как видно из табл. 1.3, они никак не связаны с диапазонами соответствующих физических типов. Обратите внимание, что в Delphi по умолчанию задано 32-разрядное представление. Таблица 1.3. — Логические целые типы
Совет:В С и C++ для целых значений определены типы int, short int (или просто short) и long int (или просто long). Тип int из C/C++ соответствует типу Integer из Delphi, a long из C/C++ — Longint из Delphi. Однако Shortint из C/C++ соответствует в Delphi не Shortint, a Smalltlnt. Эквивалент Shortint из Delphi в C/C++— это signed char. Тип unsigned char в C/C++ соответствует типу Byte из Delphi. В C/C++ существует еще тип unsigned long, аналога которому в Delphi нет. Над целыми данными выполняются все операции, определенные для порядковых типов, но с ними все же удобнее работать как с числами, а не с «нечисленными порядковыми типами». Как и «живые» числа, данные целых типов можно складывать (+), вычитать (-) и умножать (*). Однако некоторые операции и функции, применяемые к данным целых типов, имеют несколько иной смысл.
Совет:Будьте внимательны при перенесении численных выражений из одного языка в другой. В Basic, например,vфункция SQR вычисляет квадратный корень. В C/C++ целое деление обозначается косой чертой (/). В Delphi косая между двумя целыми даст действительный результат с плавающей запятой. Символьные типыСмысл символьных данных очевиден, когда они выводятся на экран или принтер. Тем не менее, определение символьного типа может зависеть от того, что подразумевать под словом символ. Обычно символьные типы данных задают схему взаимодействия между участками памяти разного объема и некоторым стандартным методом кодирования/декодирования для обмена символьной информацией. В классическом языке Pascal не задано никакой схемы, и в конкретных реализациях применялось то, что на том же компьютере мог использовать каждый. В реализациях языка Pascal для первых микропроцессоров была применена 7-битовая схема, названная ASCII (American Standard Code for Information Interchange — Американский стандартный код для обмена информацией). Эта схема и поныне широко распространена, но информация хранится, как правило, в 8-битовых участках памяти. Дополнительный бит удваивает число возможных представлений символов, но реализации расширенного набора символов ASCII часто бывают далеки от стандарта. В данной версии Delphi определен набор 8-битовых символов, известный как расширенный (extended) ANSI (American National Standards Institute — Американский национальный институт стандартов). Как бы то ни было, символьную схему приходится воспринимать так, как ее воспринимает операционная система. Для оконных операционных систем фирмы Microsoft это схема ANSI, включающая ограниченное число предназначенных для вывода международных знаков. В стремлении же применить более обширный набор международных знаков весь компьютерный мир переходит к 16-битовой схеме, именуемой UNICODE, в которой первые 256 знаков совпадают с символами, определенными в схеме ANSI. Для совместимости со всеми этими представлениями в Object Pascal определены два физических символьных типа и один логический. Физические типы перечислены ниже.
Символьные типы объемом в двойное слово (32 бит) отсутствуют. Логический символьный тип именуется char. В классическом языке Pascal char— единственный символьный тип. В Delphi char всегда соответствует физическому типу данных AnsiChar. У американских программистов ассоциация символа с однобайтовой ячейкой памяти укоренилась за долгие годы настолько, что им зачастую просто не приходит в голову, что можно использовать другие схемы кодирования. Однако дискуссии по интернационализации программ в Internet и World Wide Web могут существенно изменить их отношение к проблеме объема символьных данных. Применяя логический тип char, следует делать реализации для других микропроцессоров и операционных систем, в которых char может определяться как WideChar. При написании программ, которые могут обрабатывать строки любого размера, для указания этого размера рекомендуется применять функцию SizeOf, не задавая ее жестко постоянной. Функция Ord (С), где С — любая переменная символьного типа, возвращает целое значение, которым символ С представлен в памяти.
Совет:Процессор не различает типы char, определенные в C/C++ и Delphi. Однако функционально каждый из этих языков трактует данный тип совершенно по-разному. В C/C++ это целый тип, переменной которого можно присваивать целые значения. Переменной int можно присвоить символьное значение, а переменной char — целое. В Delphi символьные типы жестко отделены от численных. Для присвоения численному значению символьного здесь необходимо воспользоваться функцией Ord. В языке Basic один символ представляется так же, как и строка символов. Функция Chr из Delphi эквивалентна функции CHR$ из Basic. Функция Ord из Delphi, возвращающая код ANSI символьной переменной, подобна функции A3 С из Basic, аргумент которой представляет односимвольную строку. Булевы типыНа ранней стадии обучения программисты осваивают понятие бита, два состояния которого можно использовать для записи информации о чем-либо, представляющем собой одно из двух. Бит может обозначать 0 или 1, ДА или НЕТ, ВКЛЮЧЕНО или ВЫКЛЮЧЕНО, ВЕРХ или НИЗ, СТОЯТЬ или ИДТИ. В Object Pascal информация о чем-либо, что можно представить как ИСТИНА (True) или ЛОЖЬ (False), хранится в переменных булевых типов. Всего таких типов че-тыре, и они представлены в табл. 1.4. Таблица 1.4. — Размеры переменных булевых типов
По аналогии с целыми и символьными типами, подразделяющимися на физические и логические, естественно предположить, что ByteBool, WordBool и LongBool — физические типы, Boolean — логический. Но в данном случае это не совсем так. Все четыре типа различны. Для Object Pascal предпочтителен тип Boolean, остальные определены для совместимости с другими языками программирования и операционными системами. Переменным типа Boolean можно присваивать только значения True (истина) и False (ложь). Переменные ByteBool, WordBool и LongBool могут принимать и другие порядковые значения, интерпретируемые обычно как False в случае нуля и True — при любом ненулевом значении. Совет:Булевы типы в Delphi можно сравнить с типом LOGICAL языка FORTRAN. В Basic, С и C++ булевы типы как таковые отсутствуют. Булевы выражения в этих языках применяются точно так же, как во всех остальных, однако результаты этих выражений интерпретируются не как значения отдельного типа, а как целые числа. Как в Basic, так и в C/C++ булевы выражения дают численные результаты, интерпретируемые как False в случае 0 и True — в случае любого ненулевого значения. Это совместимо с порядковыми значениями булевых выражений в Delphi. В C/C++ простые сравнения дают результат 1 (True) или 0 (False). Это эквивалентно булевым значениям Delphi. Только результат сравнения в Delphi выводится как булевый, а не целый. В большинстве случаев типу Boolean из Delphi соответствует тип char в C/C++. В Basic зарезервированы слова TRUE (эквивалентно константе -1) и FALSE (эквивалентно константе 0). В Basic TRUE меньше FALSE, в Delphi, наоборот, False меньше True. Перечислимые типыОбычно данные перечислимых типов содержат дискретные значения, представляемые не числами, а именами. Тип Boolean— простейший перечислимый тип в Object Pascal. Булевы переменные могут принимать два значения, выражаемые именами True и False, а сам тип определен в Object Pascal так, как будто он объявлен следующим образом: С помощью типа Boolean в Object Pascal выполняются сравнения, большинство же перечислимых типов — это просто списки уникальных имен или идентификаторов, зарезервированных с конкретной целью. Например, можно создать тип MyColor (мой цвет) со значениями myRed, myGreen и myBlue (мой красный, мой зеленый, мой синий). Это делается совсем просто: В этой строке объявлены четыре новых идентификатора: MyColor, myRed, myGreen и myBlue. идентификатором MyColor обозначен порядковый тип, следовательно, в синтаксисе Object Pascal можно применять этот идентификатор везде, где разрешены перечислимые типы. Остальные три идентификатора— это значения типа MyColor. Подобно символьным и булевым типам перечислимые не являются числами, и использовать их наподобие чисел не имеет смысла. Однако перечислимые типы относятся к порядковым, так что значения любого такого типа упорядочены. Идентификаторам в списке присваиваются в качестве порядковых номеров последовательные числа. Первому имени присваивается порядковый номер 0, второму — 1 и т.д. Совет:В С и C++ есть тип enema, аналогичный перечислимому типу Delphi. Но в этих языках можно произвольно присваивать идентификаторам постоянные значения. В Delphi же соответствие имен и их значений фиксировано: первому имени присваивается значение 0, каждому последующему — на единицу больше. В С тип enum применяется лишь как средство быстрого определения набора целых постоянных. В C++ объявленные в перечислимом типе идентификаторы можно присваивать только переменным того же типа. Поддиапазонные типыПеременные поддиапазонного типа содержат информацию,соответствующую некоторому pаданному диапазону значений исходного типа, представляющего любой порядковый тип, кроме поддиапазонного. Синтаксис определения поддиапазонного типа имеет следующий вид: Поддиапазонные переменные сохраняют все особенности исходного типа. Единственное отличие состоит в том, что переменной поддиапазонного типа можно присваивать только значения, входящие в заданный поддиапазон. Контроль за соблюдением этого условия задается командой проверки диапазона (range checking). Необходимость явно определять поддиапазонный тип возникает нечасто, но все программисты неявно применяют эту конструкцию при определении массивов. Именно в форме поддиапазонной конструкции задается схема нумерации элементов массива. Действительные типыВ переменных действительных типов содержатся числа, состоящие из целой и дробной частей. В Object Pascal определено шесть действительных типов. Все типы могут представлять число 0, однако они различаются пороговым (минимальным положительным) и максимальным значениями, которые могут представлять, а также точностью (количеством значащих цифр) и объемом. Действительные типы описываются в табл. 1.5. Таблица 1.5. Действительные типы.
Совет:Тип Real предназначен для совместимости с ранними версиями Delphi и Borland Pascal. Формат этого типа неудобен для семейства процессоров Intel, поэтому операции с типом Real выполняются несколько медленнее операций над остальными действительными типами. Целые типы представляют целые числа, т.е. числа, дробная часть которых равна нулю. Разница между двумя неодинаковыми целыми числами не может быть меньше единицы. Именно благодаря этому целые числа применяются для обозначения дискретных величин, независимо от того, имеют ли реальные объекты какое-либо отношение к числам. Действительные типы предназначены для представления чисел, которые могут иметь дробную часть, поэтому они полезны для представления величин, которые могут быть довольно близкими, почти непрерывными. Заметьте, именно почти. Несмотря на название действительные, переменные этих типов отличаются от математических действительных чисел. В Object Pascal действительный тип — это подмножество математических действительных чисел, которые можно представить в формате с плавающей запятой и фиксированным числом цифр. Для невнимательных программистов ситуация усугубляется тем, что в стандартных форматах IEEE (Institute of Electrical and Electronic Engi-neers — Институт инженеров- электриков и электронщиков), применяемых в программах Delphi и вообще в большинстве программ для Windows, возможно точное представление только чисел с фиксированным числом бит в дробной части. Удивительно, но такое простое число, как 0,1, записывается в расширенном формате IEEE с некоторой погрешностью, пусть очень небольшой. Из-за этого представление с плавающей запятой оказывается несколько неудобным для программ, в которых сохраняется и выводится фиксированное число десятичных разрядов численных значений. Это относится и к программам, работающим с »живыми» деньгами. Для частичного решения этой проблемы в Object Pascal определены два формата с фиксированной запятой. Тип Comp (computational — вычислительный) содержит только целые числа в диапазоне от -2 63 +1 до 2 63 -1, что примерно соответствует диапазону от —9,2х10 18 до 9,2х10 18 . При программировании операций с американской валютой разработчикам обычно приходится искать естественный способ записи денежных сумм, в котором целая часть числа определяет количество долларов, дробная — центов. Если такие значения записывать в переменные типа Comp, придется представлять их в виде целого числа центов. В этом случае следует умножать значение на 100 для обращения центов в доллары, а затем делить на 100, чтобы снова получить центы. Этих забот можно избежать, если воспользоваться типом Currency. В этом случае задачу выбора масштаба возьмет на себя компилятор. Физически значения Currency записываются в память того же объема, что и Comp, как целые числа, однако компилятор не забывает вовремя разделить значение на 10 000 (не на 100!) для его приведения в соответствие с денежным знаком и умножить на 10 000 перед записью в память. Это обеспечивает абсолютную точность в четыре десятичных знака после запятой. В Delphi есть модуль System, содержащий ряд процедур обработки данных действительных типов. Наиболее распространенные из них перечислены в табл. 1.6. Много полезных процедур содержится также в модулях SysUtils и Math. Таблица 1.6 — Функции действительных типов
Совет:Будьте внимательны при переносе численных выражений из одного языка в другой. В Basic функция SQR вычисляет квадратный корень, а функция Sqr из Delphi — квадрат числа. Для вычисления квадратного корня в Delphi применяется функция Sqrt. Иллюстрированный самоучитель по Delphi 7 для начинающихЯзык программирования Delphi. Типы данных.Вещественный типЯзык Delphi поддерживает шесть вещественных типов: Real48, single, Double, Extended, comp, Currency. Типы различаются между собой диапазоном допустимых значений, количеством значащих цифр и количеством байтов, необходимых для хранения данных в памяти компьютера (табл. 1.2). Таблица 1.2. Вещественные (дробные) типы.
Язык Delphi поддерживает и наиболее универсальный вещественный тип – Real, который э квивалентен Double. Символьный типЯзык Delphi поддерживает два символьных типа: Ansichar и Widechar:
Object Pascal поддерживает и наиболее универсальный символьный тип – Char, который эквивалентен Ansichar. Строковый типЯзык Delphi поддерживает три строковых типа: shortstring, Longstring и WideString:
В языке Delphi для обозначения строкового типа допускается использование идентификатора string. Тип string эквивалентен типу shortstring. В языке Delphi для обозначения строкового типа допускается использование идентификатора string. Тип string эквивалентен типу shortstring. Логический типЛогическая величина может принимать одно из двух значений True (истина) или False (ложь). В языке Delphi логические величины относят к типу Boolean. Comp — Тип DelphiДанные в компьютере можно рассматривать как ячейки памяти, имеющие свои имена (идентификаторы). Все данные в программе на языке Delphi должны быть описаны до их первого использования. И компилятор следит, чтобы в программе они использовались в соответствии с этим описанием, что позволяет избежать ошибок. Любая величина в Delphi может быть постоянной или переменной. Её имя (идентификатор) может состоять из комбинации латинских букв, цифр и знака подчёркивания, и начинаться не с цифры. При этом регистр символов значения не имеет. Место описания данных в программе — вне логических блоков begin / end. В модуле перед ключевым словом implementation есть блок описания: Именно здесь, начиная со следующей строки, удобно объявлять глобальные переменные и константы. Как видим, одна (Form1) уже есть! Команда объявления переменных в языке Delphi: var имя_переменной : тип_переменной ; Слово var — ключевое. Именем может быть любой идентификатор, если он не был описан ранее и не является одним из ключевых или зарезервированных слов языка Delphi. Если нужно описать несколько переменных одного типа, то их перечисляют, отделяя запятой: Если несколько описаний следуют друг за другом, то ключевое слово var повторно можно не указывать: Постоянную величину иначе называют константой. Конечно, в программе можно использовать числа и строки непосредственно: 3.1415 или ‘Это значение числа пи’ , но иногда удобнее присвоить их идентификатору. Описание констант аналогично описанию переменных, но используется ключевое слово const, за именем идентификатора следует тип, затем знак равенства и его значение. Причём тип константы допускается не указывать: const pi= 3.1415 ; К слову, константа Pi встроенная в Delphi, то есть для того чтобы использовать в Delphi число 3,1415. в расчётах, нужно просто присвоить встроенную константу Pi переменной типа Real или просто использовать непосредственно в выражениях. Теперь пришло время узнать о типах данных, используемых в Delphi. Прежде всего это строки и числа. Строкой называется последовательность символов, заключённая в одиночные кавычки: Числа бывают целые и дробные.
Дробные числа имеют дробную часть, отделяемую десятичной точкой. Допускается использование символа e (или E), за которым следует число, указывающее, что левую часть нужно умножить на 10 в соответствующей степени: 5e25 — пять умножить на десять в двадцать пятой степени.
Следующим типом данных является логический Boolean, состоящий всего из двух значений: True (Истина) и False (Ложь). При этом True > False. Теперь, используя компоненты, их свойства и события, вводя собственные переменные, можно конструировать программы, содержащие вычисления. Осталось узнать, как вычисленное значение вывести на экран. var A, B, C: Integer ; вызовет ошибку, так как свойство Caption имеет текстовый тип String, а использованные переменные — цифровой тип Integer. Значит, нужно преобразовать значение переменной C в текстовый тип. Для этого есть встроенная функция IntToStr. Строка в нашей «программе», вызывавшая ошибку, должна выглядеть так: Такая программа, кроме показа числа 15, ни на что не способна. Мы должны научиться вводить в программу другие числа. Используем компоненты Edit. Введённые числа будут содержаться в свойстве Text этих компонентов. Расположим на форме два компонента Edit, один компонент Label и кнопку Button, по нажатию на которую и будем проводить вычисления. В компоненты Edit1 и Edit2 будем вводить числа для суммирования. Чтобы переместиться в редактор кода, щёлкнем дважды по нашей кнопке Button1. Мы попадём прямо в сформированную для нас средой Delphi заготовку обработчика нажатия на кнопку, непосредственно между операторами begin и end. Напишем такой простой код: procedure TForm1.Button1Click(Sender: TObject); При попытке исполнить этот код Delphi покажет ошибки по аналогичной причине — переменные A и B имеют цифровой тип Integer, а свойство Text — текстовый тип String. Исправить ошибки поможет встроенная функция StrToInt, выполняющая обратное преобразование — текст в целое число. Операторы присвоения переменным A и B должны выглядеть так: A := StrToInt(Edit1.Text); В данном случае переменные A, B, C использовались для наглядности. Можно обойтись одной строчкой: Аналогично, имеются функции и для преобразования в строку и обратно действительных чисел c плавающей (Floating англ.) запятой, имеющих тип Real. Для преобразования в строку — FloatToStr, обратно — StrToFloat. Comp — Тип DelphiПоставил 7 дельфи и столкнулся с проблемой при установке компанента. В 6 версии все было ОК. Вот куски кода: . У тебя есть тип Int64 типа record с полем QuadPart, ну или класс, объект? Проверь определение D4PLUS, в Delphi 7 — VER150, Delphi 6 — VER140 Windows.pas — и в 6 и в 7 одинаковый ULARGE_INTEGER = record я так понимаю, что в 7 просто не определена директива D4PLUS Я просто убрал определение версии Дельфи и все заработало, но столкнулся с другой немного проблемой: op0,op1: TLargeInteger; |