tuzik87@inbox.ru писал(а):Термин "перезагрузка " по отношению к подпрограммам давно применяется в технической литературе.
overload во всех словарях преводится как "перегрузка". Я не поленился, поспрашивал Гугла, но он мне ни одного варианта использования слова "перезагрузка" в данном контексте, кроме вашего, не выдал. А слово "переЗАгузка" переводится либо как reset, либо как reboot, или в крайнем случае reload.
tuzik87@inbox.ru писал(а):Функция Length упоминается в главе посвященной строкам.
Из своего опыта обучения программированию, один из самых распространённых вопросов: "а как определить длину динамического массива?". Если уж вы делаете справочник, то группируйте всю полезную информацию по теме в одном месте, чтобы не приходилось искать по всей книге.
Кстати, у функции Setlenght есть вариант для многомерных массивов.
tuzik87@inbox.ru писал(а): БНФ мне кажется неудобной для восприятия.
!!! Отлично! Вы меня порадовали! Вы считаете, что ваша форма записи более удобна для полноценного описания синтаксиса конструкций?!
А то, что используются английские слова для ключевых конструкций языка вам не кажется неудобным для восприятия?
В мире программирования уже давно есть определённые стандарты, которые придуманы были, я вас уверяю, весьма не глупыми людьми. Может быть, конечно, вы сможете удивить мир программистов и придумать что-то более удобное и эффектвиное, чем БНФ, може быть, но пока, увы, этого не наблюдается.
Открывая справочник по языку программирования я лично ожидаю увидеть полноценное описание синтаксиса конструкций языка. Например такое, как в родной документации на Delphi или FreePascal. А если этого исчерпывающего описания нет, то зачем тогда такой "справочник"?
P.S. сегодня не было времени почитать дальше, поэтому новых замечаний пока нет.
Добавлено спустя 10 часов 20 минут 6 секунд:Продолжим.
Глава 10. Инкремент и декремент
Инкрементом называется увеличение значения на единицу. Декремент выполняет обратное действие. Для этих операций предусмотрены две подпрограммы. Подпрограмма Inc выполняет инкремент. Подпрограмма Dec выполняет декремент. Они берут имя переменной как аргумент.
inc и dec в языке pascal позволяют изенять только целочисленные переменные или перечислимые типы, например Char, причём не только на единицу. Если указать вторым параметром приращение, то значение будет увеличено или уменьшено на это значение.
При этом у данных функций есть особенность при работе с типизированными указателями. При вызове inc для типизированного указателя приращение происходит на величину SizeOf(type). Пример:
- Код: Выделить всё
type
TPoint = record
x: integer;
y: integer;
end;
PPoint = ^TPoint;
var
MyPoint: PPoint;
ArrPoint: array[1..10] of TPoint;
begin
...
MyPoint := @ArrPoint[1]; //переменная MyPoint указывает на ArrPoint[1]
...
inc(MyPoint); //теперь MyPoint указывает на ArrPoint[2], то есть указатель сместился
//на величину SizeOf(TPoint)
...
end;
Глава 11. Работа с консолью
тут нужно сказать о том, что при выводе русского текста на консоль необходимо использовать функцию UTF8ToConsole для перекодировки символов.
Причём рекомендуется именно этот вариант, а не UTF8ToANSI, поскольку он является кроссплатформенным, а UTF8ToANSI будет работать только на Win32.
Добавлено спустя 1 час 56 минут 12 секунд:Да, из общих замечаний, было бы неплохо изменить нумерацю глав, чтобы она содержала не только порядковый номер, но и номер части. То есть, не 1. 2. 3., а 1.1. 1.2 1.3 и т.д. Тогда будет проще на них делать сноски по тексту, а также ориентироваться по тексту. А то открываешь где нибудь в середине и не понятно "Глава 6. Макросы" это какая часть?
Типизированные указатели и массивы как аргументы подпрограмм
Используйте псевдоним типизированного указателя, если хотите использовать его как аргумент подпрограммы или в качестве значения возвращаемого функцией.
Только благодаря тому, что у меня достаточно большой стаж программирования, я кое как понял, что вы тут пытались сказать. Вообще, такое ощущение, что это какой-то гулг-перевод с английского, слегка правленный вами, как-то уж слишком не по русски написано. В данном случае речь идёт не о псевдониме типизированного указателя, а об использовании типа, являющегося псевдонимом указателя на некий тип данных. То есть, приведённый выше в примере тип PPoint как раз и есть псевдоним указателя на тип TPoint.
Но аргументом процедуры или функции будет не PPoint, а параметр типа PPoint, то есть: procedure MyPoc(aPoint: PPoint);
При этом нужно указать, что использование aPoint: PPoint будет аналогично использованию var aPoint: TPoint, то есть, при изменении значения aPoint^, когда она передаётся через указатель, будут изменены данные в вызывающем модуле.
Да, и когда вы говорите об указателях, то нигде не говорите о том, какой размер занимает переменная типа Point и все прочие типизированные указатели обычных типов (не классов и не объектов). Для х86 это будет 4 байта, для х64 это будет 8 байт, а для всяческих других платформ нужно смотреть документацию по данной платформе (теоретически могут быть и 16 разрядные микроконтроллеры и 16 разрядная архитектура х86).
Освобождение выделенного блока производится подпрограммой FreeMem, которая имеет две формы. Первая ее форма берет указатель и размер области памяти в качестве аргументов. Вторая форма берет указатель на блок памяти в качестве аргумента.
На самом деле форма FreeMem(p: pointer; Size: ptruint), которая имеет два параметра, введена исключительно для совместимости со старым кодом. При работе стандартный менеджер памяти второй параметр не использует и всегда освобождает то количество памяти, которое запрашивалось при вызове GetMem. Этот размер хранится в памяти перед областью данных, которая выделяется при вызове GetMem. Это означает, что если вы запрашиваете область данных размером один байт, реально выделится как минимум 1 + 4 байта для режима x86 (DWord) или 1 + 8 байт для режима х64 (+QWord).
Добавлено спустя 2 часа 17 минут 11 секунд:Глава 16. Множества
...
Операция объединения возвращает новое множество, состоящее из элементов входящих в обе пары множеств. Пересечение состоит из элементов входящих в обе пары множеств.
И чем же в вашем объяснении операция объединения отличается от операции пересечения? В первом случае: "из элементов входящих в обе пары множеств", во втором случае: "из элементов входящих в обе пары множеств". Мне одному кажется, что эти варианты совпадают дословно?
Симметричная разность дает множество состоящие из элементов, которые не входят ни в одно из исходных множеств.
???!!! Вообще-то "симметричная разность", то бишь "symmetric difference" содержит все элементы, кроме входящих в оба множества. А ваш вариант может быть лишь пустым множеством (ну либо бесконечным, за исключением входящих в одно из исходных множеств, смотря как мы будем рассматривать пространство элементов, замкнутым или открытым).
Полное описание операций со множествами тут:
http://freepascal.org/docs-html/ref/refsu45.html#x139-14900012.8.5include и exclude повторяют + и -.
Там же есть очень хорошие примеры, которые помогают понять как это работает.
Добавлено спустя 1 час 14 минут 29 секунд:Глава 17. Обработка строк
...
AnsiString - Строка с текстом в кодировке UTF-8
Ничего подобного! AnsiString содержит строку из символов Char, длина которых 1 байт, и не более того. А уж какую кодировку вы выберите для своих строк, это ваше дело. При этом в Lazarus для среды разработки по умолчанию выбрана кодировка UTF-8, но это не означает, что в переменную AnsiString нельзя положить строку в кодировке cp1251, OEM866 или KOI8.
String - В зависимости от настроек компилятора может быть синонимом ShortString или AnsiString
Ну так и опишите где нибудь диррективу компилятора для этих целей:
{$H-} - все строки, объявленные как string, рассматриваются как ShortString[255],
{$H+} - как ShortString рассматриваются только строки, у которых явно задаётся длина строки в квадратных скобках. Остальные как AnsiString с нулём на конце.
Память под короткие строки выделяется при запуске программы.
Это не так. Память при запуске программы выделяется только под глобальные строки. Если переменная объявляется в процедуре или функции, то память будет выделяться на стеке в процессе работы. Если короткая строка является частью объекта или записи, память под которые выделяется динамически, то и память под строки в их составе также будет выделяться динамически.
Более правильно сказать, что память под короткие строки выделяется как под обычные статические переменные.
Вы ничего не говорите про систему управления памятью для длинных строк с системой ссылок и счётчиков, а также о том, что по своей сути AnsiString является аналогом PChar, то бишь указателем на строку, а WideString является аналогом PWideChar. Но при этом для строк через PChar и PWideChar система автоматического управления памятью и ссылками не применяется. На практике это может быть важно, если вы работаете с анализом и разбором текста. Система поиска копий в пуле существующих строк может существенно замедлять работу программы при большом их количестве, если используются AnsiString или WideString.
Значение, которое присваивается строковой переменной, должно быть заключено в одинарные кавычки.
А равзе такой вариант не будет работать:
- Код: Выделить всё
const
sc = 'TEST';
var
s: string;
с: Char;
begin
c := '!';
s := sc + chr(32) + c + #10#13;
end.
?
Значение, которое присваивается строковой переменной, должно быть другой строкой, символом, результатом строковой или символьной функции или строковой константой. Строка, заключённая в одинарные кавычки, тоже является строковой константой, заданой в месте присвоения.
Преобразования кодировок
Функция AnsiToUtf8 преобразует строку из текущей системной кодировки в UTF-8. Функция Utf8ToAnsi выполняет обратное преобразование.
И это всё? А как же UTF8ToUnicode, UTF8ToSys, UTF8ToConsole и обратные им?
Правда, для последних двух требуется подключение модуля LazUTF8, зато они обеспечивают кроссплатформенность приложения.
Кстати, весьма интересно, как реализована функция UTF8ToAnsi. Вначале строка UTF8 декодируется в строку Unicode, то бишь WideString, а после этого присваивается строке AnsiString. То есть, дальше задействуется штатный механизм компилятора по преобразованию WideString в AnsiString. В обратную сторону точно так же.
Интересно, а движок FreePascal поддерживает сохранение текущей кодовой таблицы для AnsiString перед самой строкой, как это сделано в Delphi или нет? Я что-то пока про это ничего не нашёл.
Переменным типа Variant можно присваивать целочисленные и дробные переменные, а так же строки и интерфейсы.
А также значениz varNull и varEmpty, то не одно и тоже. Для проверки на эти значения используются функции function VarIsNull(v: variant): boolean и function VarIsEmpty(v: variant): boolean. Только нужно не забывать подлкючать модуль variants для их использования.
И вообще, про тип variant как-то мало написано, хотя тема эта достаточно большая и сложная.
Добавлено спустя 7 часов 55 минут 48 секунд:продолжаем...
Глава 18. Записи
А где описание записи с вариантами с использованием ключевого слова case?
- Код: Выделить всё
type
BetterRPoint = Record
Case UsePolar : Boolean of
False : (X,Y,Z : Real);
True : (R,theta,phi : Real);
end;
Файлы бывают следующих типов: текстовые, типизированные и двоичные. Типизированные файлы состоят из записей блоков типа.
Опять гугл-переводчик?
Типизированные файлы хранят набор записей указанного типа. Если тип будет integer, то в файле будет набор целых чисел. Если укажем тип record, например TPoint, то в файле будут записи экземпляров TPoint.
И справочник по функциям как-то бедноват.
Тут полный список функций для работы с файлами в модуле system
http://freepascal.org/docs-html/rtl/system/filefunctions.htmlТут набор функций для работы с файловой системой из модуля dos
http://freepascal.org/docs-html/rtl/dos/filehandling.htmlТут набор функций для работы с дисками и файлами из модуля Sysutils
http://freepascal.org/docs-html/rtl/sysutils/filenameroutines.htmlГлава23. Структура программы
В отличие от первых редакций языка Pascal, современыне редакции, что в Delphi, что в FreePascal не стаят жёстких условий на порядок следования секций в программе или модуле.
Любоая программа может иметь следующие необязательные секции, некоторые из которых выделяются ключевыми словами:
uses - подключение внешних модулей, используемых в программе;
const - сеция объявления глобальных констант;
type - секция объявления глобальных типов;
var - секция объявления глобальных переменных;
- секция определения процедур и функций.
Секции const, type, var и определения процедур и функций может быть столько, сколько нужно и они могут следовать в произвольном порядке.
После всех объявлений и определений идёт собственно основное тело программы:
- Код: Выделить всё
begin
{операторы}
end.
При этом после слова end ставится точка. Это последний end, после которого компилятор остальной текст не обрабатывает, можете там писать что угодно.
При чередовании секций с объявлениями нужно помнить следующие правила:
1. То что вы собираетесь использовать в правой части ваших определений констант, типов, переменных или параметров процедур и функций, должно быть объявлено либо выше по тексту, либо в модулях, которые вы подключаете к программе в секции uses.
2. При предварительном объявлении типов или классов окончательное определение класса дожно быть сделано в той же секции type, что и предварительное объявление. Между предварительным объявлением и окончательным не должны вставляться другие секции, например const.
В отличе от некоторых других языков, например C или C++, язык Pascal позволяет писать вложенные процедуры и функции. В принципе, любая процедура или функция может после своего заголовка содержать свой набор секций const, type, var, а также вложеные процедуры и функции, которые описываются до блока begin...end; в котором определяется действие самой процедуры или функции. При этом вложенные процедуры и функции, в свою очередь, могут содержать собственные внутренние секции и процедуры и функции. В описании FreePascal я с ходу не нашёл, но для старых компиляторов фирмы Borland максимальный уровень вложенности равнялся семи (7). Кстати, максимальная рамзеность массивов и уровень вложенности выражений со скобками тоже была равна 7, видимо это какое-то магическое число
.
Теперь что касается области видимости констант, типов и переменных.
Если мы определяем вложенные процедуры и фукнции внутри других процедур и функций, то для них будут видны все определения и переменные, которые объявлены в сециях const, type и var, которые находятся выше определения вложенной процедуры или функции. При этом ничто не мешает нам добавить другие секции const, type и var уже после определения вложенной процеудуры или функции. Соответственно, в этой вложенной процедуре или функции данные определения использовать нельзя, а в основной процедуре или функции они будут работать.
Если имеется несколько определений констант, типов или переменных с одинаковыми именами в разных областях видимости, то действует то, которое к данному блоку begin...end ближе, если смотреть по коду снизу вверх. То есть, если мы объявили глобальную переменную i:integer в самой программе, а потом ещё две переменных i: integer в процедуре и вложенной в неё функции, то мы фактически получим три разных переменных i, действующих какждая в своей части кода (в своём блоке begin...end).
Также важно знать, что память под переменные, которые объявляются внутри процедур и функций, выделяется на стеке. Поэтому не следует определять большое количество локальных переменных, особенно статических массивов большой длины или размерности, поскольку это может привести к нехватке и переполнению стека, что может вызвать всевозможные трудно уловимые ошибки и сбои в работе программы.
Отдельное замечание по области видимости опредлений при использовании модулей. Разные модули могут содержать определения сущностей с совпадающими именами. Действующим будет считаться то описание, которое компилятор "видел" последним. То есть, если у вас есть несколько определений типа TPoint, одно с целочисленными полями в мдуле А, а другое с веществеными в модуле B, то всё будет зависит какой из модулей в секции uses стоит последним. Для варианта uses A, B; в вашё программе или модуле будет действовать тип с вещественными полями из модуля В. Если же вы всё таки захотите использовать TPoint с цеыми полями из модуля А, то вам придётся явно указывать имя модуля перед указаением типа:
- Код: Выделить всё
unit A;
type
TPoint = record
x, y: integer;
end;
....
unit B;
type
TPoint = record
x, y: double;
end;
...
uses A, B;
var
DoublePoint: TPoint;
IntPoint: A.TPoint;
На практике подобных вещей следует избегать, поскольку в большинстве случаев это в конечном итоге приводит к массе потерянного времени при очередном поиске ответа на вопрос: "какого хрена этот дурацкий компилятор даёт ошибку, когда у меня всё правильно?!". Но, к сожалению, огромное количество различных модулей, написанного разными людьми, которые приходится использовать в больших проектах, иногда заставляет прибегать к подобному шаманству.
Глава 3. Параметры командной строки
Параметры передаются в командной строке и разделяются пробелами. Строковая константа в двойных кавычках считается одним параметром и может внутри содежать пробелы. Именно так передаются длинные имена файлов, которые содержат пробел.
Даже если пользователь не задал ни одного парамтера при запуске программы, всегда существует параметр ParamStr[0], коорый содержит имя исполняемого файла данной программы. Если каталог запуска программы отличается от текущего или рабочего каталога, то данный параметр будет кроме имени содержать ещё и полный путь к исполняемому файлу в файловой системе.
Если вы свяжете какое либо расширение файлов с вашей программой в проводнике Windows, то при двойном клике на файле с таким расширением будет запускаться ваша программа, а в ParamStr[1] будет находится полное имя этого файла.
Глава 4. Обработка ошибок
При использовании конструкций try .. except .. end; или try .. finally .. end; они перехватывают только те ошибки, которые происходят после слова try, в том числе во время выполнения процедур и функций, которые вызываются внутри этого блока. У вас написано так, что можно подумать, будто перехватываются любые ошибки в программе.
При возникновении ошибки внутри секции try .. except .. end; после входа в секцию except и выполнения находящихся там операторов, состояние ошибки сбрасывается.
При возникновении ошибки внутри секции try .. finally .. end; выполняются операторы из секции finally, но состояние ошибки остаётся.
Соответственно, если у нас имеется несколько вложенных друг в друга секций try, то в случае с finally мы пройжём по всем из них и в конечном итоге получим на экране сообщение об ошибке для пользователя. В случае с except программа будет считать, что вы решили проблему и ошибка устранена.
То есть, конструкция except применяется в тех случаях, когда мы считаем, что можем исправить ошибочную ситуацию и продолжить нормальную работу программы.
Конструкция finally применяется в тех случаях, когда требуется обязательно выполнить какие-то действия, не взирая на возникновение ошибки, например, освободить память или закрыть открытый на чтение или запись файл данных.
Также полезно знать, что если при выполнении опертаоров после except или finally возникает повторная исключительная ситуация и генерируется ещё одна ошибка, то работа программы будет аварийно завершена без всяких предупреждений и сообщений. Поэтому в данных секциях желательно писать минимум кода и очень внимательно его проверять.
Да, кстати, в секции except можно не указывать тип исключения, в этом случае имеющийся там код будет срабатывать для любого исключения.
Также внутри секций except и finally мжно обращаться к служебной переменной E являющейся экземпляром класса Exception или его наследником, которая содержит свойства E.HelpContext и E.Message. Последнее содержит текст, который будет выведен пользователю в сообщении об ошибке. Оно же задаётся в конструкторе при генерации исключительной ситуации оператором raise.