Приложения
Приложение А. Функции, константы и структуры RDS
А.1. Типы параметров
А.1.2. Выравнивание полей служебных структур
Во многих случаях для передачи данных между пользовательской моделью блока или внешним модулем и главной программой RDS используются структуры данных. Иногда они заполняются в RDS и считываются в модуле пользователя (например, структура данных блока), иногда наоборот, заполняются в модели и считываются в RDS при вызове одной из сервисных функций. Эти структуры описаны в файле заголовков «RdsDef.h».
Поскольку разные модули могут быть созданы при помощи разных компиляторов, необходимо, чтобы поля скомпилированных структур имели одинаковые смещения в байтах от начала структуры и в RDS, и в пользовательском модуле – например, в модели блока. Это достигается принудительным выравниванием полей по границам шестидесятичетырехбитных (восьмибайтовых) слов в описаниях структур. Для этого каждое поле в каждой структуре описано как на анонимное объединение (union), состоящее из самого поля и дополнительного служебного поля размером в 8 байтов (для полей-массивов служебные поля тоже будут массивами).
Рассмотрим для примера условную структуру следующего вида:
typedef struct { char cField; // Односимвольное поле (1 байт) double dField; // Вещественное поле (8 байтов) int iField; // Целое поле (4 байта) } RDS_SOMESTRUCT;
Здесь поле cField имет нулевое смещение относительно начала струкутры. Смещения остальных полей определяются настройками компилятора. При плотной упаковке, например, поле dField будет иметь смещение 1 (перед ним – один байт), поле iField – смещение 9 (перед ним – один байт и восемь байтов). При других параметрах смещения dField и iField могут быть 8 и 16 байтов соответственно (выравнивание Quad Word). В главной программе RDS и моделях блоков параметры выравнивания должны быть одинаковыми, иначе кто-то из них будет обращаться «мимо» полей структуры, заполненной другим. Во многих случаях выравнивание данных можно указать в параметрах компилятора при его запуске, однако, RDS и DLL моделей блоков могут компилироваться разными компиляторами с разными возможностями и настройками. По этой причине описания структур RDS сделаны таким образом, чтобы одинаковое выравнивание обеспечивалось автоматически.
Если все поля структуры имеют одинаковый размер, с большой вероятностью они будут расположены друг за другом без зазоров. Поэтому приведенная выше структура в «RdsDef.h» во второй версии RDS имела бы следующий вид:
typedef struct { union { char cField; // Односимвольное поле (1 байт) double align0; // Служебное поле для выравнивания }; union { double dField; // Вещественное поле (8 байтов) double align1; // Служебное поле для выравнивания }; union { int iField; // Целое поле (4 байта) double align2; // Служебное поле для выравнивания }; } RDS_SOMESTRUCT;
Здесь анонимное объединение, в которое входит каждое поле исходной структуры, всегда занимает 8 байтов, независимо от размера самого поля. Таким образом, смещения полей cField, dField и iField будут равны 0, 8 и 16 соответственно, независимо от того, какой компилятор будет обрабатывать исходный текст модели. Поля align0, align1 и align2 – служебные, и обращаться к ним в программе не следует (это бессмысленно). Последнее из выравнивающих полей (align2), очевидно, не требуется, хотя и не мешает (оно добавлено при автоматическом формировании файла «RdsDef.h»).
Поле align1 тоже, в принципе, не требуется (dField и так имеет нужный размер), но, в отличие от этого примера, в настоящем «RdsDef.h» в качестве типа для выравнивания вместо double используется платформо-зависимая константа RDSBIGGESTTYPE. Для платформы Win32 в качестве этого «выравнивающего» типа используется double, для платформы Win64 – void*. Это самые большие по размеру типы, используемые в описаниях RDS.