Типы данных в языке IDL

21 мая 2024

ID ice_idl_data_types

В языке 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);

}

Вам помогла эта статья?
Что нам нужно улучшить?
Спасибо за ваш отзыв, вы помогаете нам становиться лучше!
Спасибо за ваш отзыв, вы помогаете нам становиться лучше!