В языке IDL поддерживаются как примитивные, так и составные типы данных. Набор поддерживаемых составных типов включает объединения, структуры, массивы и последовательности.
Примитивные типы
В языке IDL поддерживаются следующие примитивные типы:
SInt8
, SInt16
, SInt32
, SInt64
– знаковое целое число.UInt8
, UInt16
, UInt32
, UInt64
–беззнаковое целое число.Handle
– значение, двоичное представление которого состоит из нескольких полей, включая поле дескриптора и поле маски прав дескриптора.bytes<
<размер в байтах
>>
– байтовый буфер, представляющий собой область памяти с размером, не превышающим заданного числа байт.string<
<размер в байтах
>>
– строковый буфер, представляющий собой байтовый буфер, последний байт которого является терминирующим нулем. Максимальный размер строкового буфера на единицу больше заданного из-за наличия дополнительного байта с терминирующим нулем.Целочисленные литералы можно указывать в десятичном, шестнадцатеричном (например, 0x2f
, 0X2f
, 0x2F
, 0X2F
) или восьмеричном (например, 0O123
, 0o123
) представлении.
С помощью ключевого слова const
можно определять именованные целочисленные константы, задавая их значения целочисленными литералами или целочисленными выражениями.
Примеры определений именованных целочисленных констант:
const UInt32 DeviceNameMax = 0o100;
const UInt32 HandleTypeUserLast = 0x0001FFFF;
const UInt32 MaxLogMessageSize = (2 << 3) ** 2;
const UInt32 MaxLogMessageCount = 100;
const UInt64 MaxLen = (MaxLogMessageSize + 4) * MaxLogMessageCount;
Именованные целочисленные константы можно использовать, чтобы избежать проблемы "магических чисел". К примеру, если в IDL-описании определены именованные целочисленные константы для кодов возврата интерфейсного метода, то при описании политики можно интерпретировать эти коды без дополнительных сведений. Также именованные целочисленные константы и целочисленные выражения могут применяться в определениях байтовых и строковых буферов, а также составных типов, чтобы задать размер данных или число элементов данных.
Конструкции bytes<
<размер в байтах
>>
и string<
<размер в байтах
>>
используются в определениях составных типов, сигнатурах интерфейсных методов и при создании псевдонимов типов, так как сами по себе они определяют анонимные типы (типы без имени).
Объединения
Объединение позволяет хранить данные разных типов в одной области памяти. В IPC-сообщении объединение снабжается дополнительным полем tag
, позволяющим определить, какой именно член объединения используется.
Для определения объединения используется следующая конструкция:
union <имя типа> {
<тип члена> <имя члена>;
[...]
}
Пример определения объединения:
union ExitInfo {
UInt32 code;
ExceptionInfo exc;
}
Структуры
Для определения структуры используется следующая конструкция:
struct <имя типа> {
<тип поля> <имя поля>;
[...]
}
Пример определения структуры:
struct SessionEvqParams {
UInt32 count;
UInt32 align;
UInt32 size;
}
Массивы
Для определения массива используется следующая конструкция:
array<<тип элементов, число элементов>>
Эта конструкция используется в определениях других составных типов, сигнатурах интерфейсных методов и при создании псевдонимов типов, так как сама по себе она определяет анонимный тип.
Тип Handle
можно использовать в качестве типа элементов массива, если этот массив не входит в другой составной тип данных. При этом суммарное число дескрипторов в IPC-сообщении не может превышать 255.
Последовательности
Последовательность представляет собой массив переменного размера. При определении последовательности указывается максимальное число ее элементов.
Для определения последовательности используется следующая конструкция:
sequence<<тип элементов, число элементов>>
Эта конструкция используется в определениях других составных типов, сигнатурах интерфейсных методов и при создании псевдонимов типов, так как сама по себе она определяет анонимный тип.
Тип Handle
нельзя использовать в качестве типа элементов последовательности.
Типы переменного и фиксированного размера
Типы bytes
, string
и sequence
являются типами переменного размера, то есть при определении этих типов задается максимальное число элементов, а фактически может использоваться меньше, в том числе ноль. Данные типов bytes
, string
и sequence
хранятся в арене IPC-сообщений. Остальные типы являются типами фиксированного размера. Данные типов фиксированного размера хранятся в фиксированной части IPC-сообщений.
Типы на основе составных типов
На основе составных типов могут быть определены другие составные типы. При этом определение массива или последовательности может быть вложено в определение другого типа.
Пример определения структуры с вложенными определениями массива и последовательности:
const UInt32 MessageSize = 64;
struct BazInfo {
array<UInt8, 100> a;
sequence<sequence<UInt32, MessageSize>, ((2 << 2) + 2 ** 2) * MessageSize> b;
string<100> c;
bytes<4096> d;
UInt64 e;
}
Определение объединения или структуры не может быть вложено в определение другого типа. Однако в определение типа могут быть включены уже определенные объединения и структуры. Это выполняется посредством указания в определении типа имен включаемых типов.
Пример определения структуры, включающей объединение и структуру:
union foo {
UInt32 value1;
UInt8 value2;
}
struct bar {
UInt32 a;
UInt8 b;
}
struct BazInfo {
foo x;
bar y;
}
Создание псевдонимов типов
Псевдонимы типов используются для повышения удобства работы с типами. Псевдонимы типов могут применяться, например, для того, чтобы задать типам с абстрактными именами мнемонические имена. Также назначение псевдонимов для анонимных типов позволяет получить именованные типы.
Для создания псевдонима типа используется следующая конструкция:
typedef <имя типа/определение анонимного типа> <псевдоним типа>
Пример создания мнемонических псевдонимов:
typedef UInt64 ApplicationId;
typedef Handle PortHandle;
Пример создания псевдонима определению массива:
typedef array<UInt8, 4> IP4;
Пример создания псевдонима определению последовательности:
const UInt32 MaxDevices = 8;
struct Device {
string<32> DeviceName;
UInt8 DeviceID;
}
typedef sequence<Device, MaxDevices> Devices;
Пример создания псевдонима определению объединения:
union foo {
UInt32 value1;
UInt8 value2;
}
typedef foo bar;
Определение анонимных типов в сигнатурах интерфейсных методов
Анонимные типы могут быть определены в сигнатурах интерфейсных методов.
Пример определения последовательности в сигнатуре интерфейсного метода:
const UInt8 DeviceCount = 8;
interface {
Poll(in UInt32 timeout,
out sequence<UInt32, DeviceCount / 2> report,
out UInt32 count,
out UInt32 rc);
}
В начало