темы вопросов
- побитовые операции (чтение, изменение битов, битовая маска, сдвиг)
- структуры (record, packed record)
- указатели (Pointer, PChar, @, ^, арифметика указателей)
- параметры var, const, out
- исключения (try, except, finally)
- управление памятью (стек, куча, выделение, освобождение, как избежать проблем (array, string))
- проектирование классов (private, public, property read write)
- управление объектами (создание, хранение и передача, освобождение, счетчик ссылок)
- контейнеры данных (TList, TStringList, TObjectList, TCollection)
- компоненты приложения (TForm, TFrame, TDataModule, TActionList, TApplicationEvents, TListView, TTreeView, режим OwnerData)
- сериализация (маршалинг) данных
- хранение, отображение, экспорт больших таблиц (больше миллиона строк)
- многопоточность, TThread.Execute, Synchronize
- потокобезопасность переменных, атомарные операции, TCriticalSection, семафоры (TEvent)
- файлы и устройства ввода-вывода (Open, Read, Write, IOCtl, Close), TStream
- последовательный порт, UART
- сокеты, TCP, UDP
- SQL, первичный ключ, индексы
- отладка, удаленная отладка, отладка по фотографии
- сборка дистрибутива (Inno Setup)
- ведение документации
побитовые операции
- чтение - операция and с маской из проверяемых битов
- установка - операция or с маской из устанавливаемых битов
- снятие - операция and с инвертированной маской снимаемых битов (операция not)
- сдвиг - операции shl, shr для получения числового значения определенной части двоичного числа. Увеличивает/уменьшает число в 2 раза на каждый бит сдвига. Неопределенные биты обнуляются.
..или использовать TBits
структуры
структура record занимает область в памяти, порядок полей фиксирован, размер полей округлен до машинного слова (для ускорения доступа к памяти). В packed record размер полей не округляется и точно соответствует типу данных. При обмене данными следует использовать packed record во избежание проблем с округлением размера.
указатели
- Pointer - переменная, указывающая на адрес в памяти, нетипизированный указатель. Типизированный указатель указывает на начало данных определенного типа.
- PChar - указатель на начало массива (строки) символов любого размера, с завершающим нулем.
- @ (в начале имени) - взятие адреса, превращает переменную в указатель
- ^ (в конце имени) - разыменовывание указателя, превращает указатель в переменную
- арифметика указателей - на указатель можно применять функции Inc() и Dec() для изменения адреса. Изменяя адрес кратно размеру элемента массива, можно получить указатель на требуемый элемент. Не рекомендуется этим пользоваться без особой необходимости.
параметры
по умолчанию параметры передаются «по значению», то есть значение копируется и изменение параметра внутри функции не отражается снаружи.
Для типов, занимающих память больше машинного слова (record, array, string, int64) рекомендуется использовать модификаторы:
- var - параметр передается как указатель (ссылка) изменение параметра внутри функции видно снаружи.
- const - параметр передается как указатель (ссылка) и защищен от изменений.
- out - то же, что и var, но предназначено только для чтения данных из функции
исключения
Ошибка в блоке try приводит к переходу в блок except, где можно предусмотреть ошибку или сообщить подробности об ошибке.
Блок finally выполняется в любом случае (была ошибка или нет), поэтому он используется для обязательных завершающих операций - возврат памяти, закрытие файлов.
управление памятью
Стек - память выделяется последовательными блоками, возвращается строго в обратном порядке. Стек используется для предопределенных переменных и параметров функций.
Куча (heap) - память выделяется и возвращается в произвольном порядке менеджером памяти. Используется для динамических массивов, строк, объектов. Работает медленней, чем стек.
Выделение памяти (GetMem() или New()) должно обязательно сопровождаться освобождением (FreeMem(), Dispose()), желательно внутри конструкции try .. finally. Иначе возникает утечка памяти.
Для избежания проблем с утечками памяти рекомендуется использовать динамические массивы (array, string), контейнеры объектов (TObjectList, TComponentList), подсчет ссылок (IInterface).
проектирование классов
- секция private - доступна только внутри класса, переменные и функции для собственных нужд
- секция public - доступна всем
- модификатор abstract задает описание метода, который должен быть реализован в классе-наследнике
- модификатор virtual разрешает переопределять метод в классе-наследнике с тем же описанием
- модификатор override переопределяет метод, описанный в классе-предке с тем же описанием
- модификатор reintroduce переопределяет описание метода класса-предка
- inherited в коде метода вызывает метод класса-предка
- property - свойство, может ссылаться на поле (переменную) или на метод класса. Модификатор read определяет поле/метод для чтения значения, модификатор write определяет поле/метод для установки значения.
- создаваемые внутри класса данные должны быть доступны в public только как read-only property, для избежания повреждения
управление объектами
Объекты создаются из классов методом класса Create() и освобождаются методом объекта Destroy()
Переменная объекта имеет тип класса и является указателем на область памяти, выделенную экземпляру класса. Объекты всегда передаются по ссылке (var).
Переменные объектов не меняют счетчик ссылок, объекты не освобождают память при отсутствии ссылок на них. Счетчик ссылок работает только для переменных типа IInterface и его наследников. Чтобы добавить в объект счетчик ссылок, нужно определить интерфейс и реализовать его в классе объекта.
контейнеры данных
для хранения данных есть стандартные контейнеры:
- TList - массив нетипизированных указателей с сортировкой
- TStringList - массив строк (с разбивкой на имя-значение) с поиском, сортировкой, привязкой объекта.
- TObjectList - массив объектов, с сортировкой и очисткой при удалении из списка
- TCollection - набор однотипных значений без сортировки, но с обратной связью (при изменении значения)
компоненты приложения
- TForm - визуальная форма в виде отдельного окна
- TFrame - визуальная форма не имеющая своего окна, для встраивания в другие формы
- TDataModule - невизуальная форма, для невизуальных контролов и манипуляций с данными
- TActionList - список действий TAction, которые можно назначать стандартным контролам (кнопкам, меню, итд)
- TApplicationEvents - обработчики по умолчанию для разных событий приложения (например, любых исключений)
- TListView - визуальный список значений, в режиме Report отображается как таблица
- TTreeView - визуальное дерево значений
- режим OwnerData для TListView и TTreeView позволяет не добавлять элементы, а отображать любое количество «пустых» элементов. При отображении элемента в окне, его данные запрашиваются в обработчике OnData.
сериализация
Сериализация (маршалинг) данных - это последовательная запись множества данных в текст или файл (для передачи по сети), с последующей десериализацией - чтением из текста/файла в исходное состояние. Важно при этом сохранить целостность данных - последовательность и размер полей, кодировку текста. Для внутренного использования предпочтительны бинарные форматы, для экспорта-импорта - текстовые (XML, JSON).
большие таблицы
Структурированные данные занимают много места в памяти и требуют значительного времени на инициализацию. Поэтому для больших объемов необходимо использовать либо базу данных, либо виртуальные таблицы, где данные по мере обращения к ним запрашиваются/вычисляются, например, из memory-mapped file. Зная номер строки и колонки, мы можем найти нужные данные в файле. При экспорте больших таблиц, следует использовать потоковый экспорт в файл нужного формата, например xls вместо экспорта в открытую таблицу Excel.
многопоточность
Все, что внутри TThread.Execute() выполняется в фоновом потоке. Методы Create(), Destroy() и остальные выполняются в основном (вызывающем) потоке, поэтому весь код фонового процесса, включая инициализацию и финализацию объектов, необходимо размещать внутри Execute(). Метод Synchronize() останавливает поток и передает выполнение указанного в параметре метода в основной поток приложения. Нельзя из TThread использовать внешние визуальные (и не только) объекты без синхронизации. Лучше вообще из TThread ничего внешнего не использовать.
потокобезопасность переменных
- Переменные размером с машинное слово или меньше - потокобезопасны, но не атомарны.
- Атомарные операции (InterlockedIncrement, InterlockedExchange, итд) блокируют доступ других потоков к переменной на время ее изменения.
- TCriticalSection создает межпоточную блокировку, кабинку, «войти» в которую может только один поток за раз, остальные будут ждать, пока блокировка освободится.
- Семафоры (TEvent) - может быть установлен (Set) или снят (Reset). Метод WaitFor() стоит и ждет, пока семафор будет кем-то установлен (Set).
файлы и устройства ввода-вывода
С точки зрения операционной системы, любое устройство, порт или источник данных можно представить как файл, который можно читать, писать и управлять.
- Open - открывает файл/устройство/порт по имени, возвращает хендл (handle) - идентификатор.
- Read - прочитать данные в буфер, с текущей позиции (если есть позиция)
- Write - записать данные из буфера с текущей позиции (если есть позиция)
- IOCtl - управление файлом/устройством/портом - чтение/запись свойств, режимов, метаданных. Например, состояние сигнальных линий для COM/LPT, настройки сокета, свойства файла или устройства.
- Close - закрытие файла/устройства, освобождение хендла
последовательный порт
Последовательный порт (COM-порт, UART) низкоскоростной аппаратный интерфейс обмена данными, где данные передаются побитно, посылками по одному символу (байту). Контроль целостности очень слабый, поэтому при пакетной передаче (множество байтов) необходимо обеспечить целостность структуры пакета (байт-стаффинг) и контроль целостности (CRC).
сокеты
Сокеты с точки зрения операционной системы, это устройства ввода-вывода, с которыми можно работать как с файлами. Помимо стандартных операций (Open, Read, Write, Close, IOCtl), доступны действия:
- Bind - привязка к IP-адресу и номеру порта (для TCP и UDP)
- Listen - открытие порта в режиме сервера, на прием входящих подключений (только для TCP)
- Accept - ожидание и прием входящего подключения, которое работает как Open отдельного сокета.
Протоколы:
- UDP - данные передаются пакетами (обычно до 1500 байт), без контроля порядка и доставки (потери) пакетов. В заголовке только адрес/порт отправителя и получателя, контрольная сумма.
- TCP - сеансовый протокол, устанавливает соединение с контролем порядка и доставки, потерянные пакеты передаются повторно.
SQL
- Structured Query Language, язык запросов к базе данных.
- первичный ключ - уникальный идентификатор строки таблицы, на который могут ссылаться другие таблицы
- индексы - «оглавление» по колонке (или нескольким колонкам), ускоряет поиск значения. Индексы ускоряют чтение и замедляют запись данных.
отладка
Запуск программы в отладчике, пошаговое выполнение, просмотр стека вызовов, текущих значений переменных, установка break-point.
Запись в лог-файл или syslog отладочных сообщений, просмотр потока сообщений в файле или терминале.
Поиск ошибки по адресу исключения (отладка по фотографии). Адрес типа 0000XXXX - переход по нулевому указателю (обращение к освобожденному объекту). Сообщения «out of range» и «range check error».
сборка дистрибутива
- makefile
- Inno Setup
ведение документации
- wiki