本节详细介绍接口定义语言(IDL)文件定义的数据类型(即Fast DDS的静态类型,与Fast DDS的动态类型区分),以及使用IDL创建数据类型的其他机制。
1、Primitive types
下表显示了Fast DDS Gen支持的基本IDL类型以及它们如何映射到C++11。
IDL | C++11 |
char | char |
octet | uint8_t |
short | int16_t |
unsigned short | uint16_t |
long | int32_t |
unsigned long | uint32_t |
long long | int64_t |
unsigned long long | uint64_t |
float | float |
double | double |
long double | long double |
boolean | bool |
string | std::string |
2、Arrays
Fast DDS Gen支持一维和多维阵列Array。数组始终映射到std::array容器。下表显示了支持的数组类型及其映射。
IDL | C++11 |
char a[5] | std::array<char,5> a |
octet a[5] | std::array<uint8_t,5> a |
short a[5] | std::array<int16_t,5> a |
unsigned short a[5] | std::array<uint16_t,5> a |
long a[5] | std::array<int32_t,5> a |
unsigned long a[5] | std::array<uint32_t,5> a |
long long a[5] | std::array<int64_t,5> a |
unsigned long long a[5] | std::array<uint64_t,5> a |
float a[5] | std::array<float,5> a |
double a[5] | std::array<double,5> a |
3、Sequences
Fast DDS Gen支持映射到std::vector容器的序列。下表表示如何处理IDL和C++11之间的映射。
IDL | C++11 |
sequence<char> | std::vector<char> |
sequence<octet> | std::vector<uint8_t> |
sequence<short> | std::vector<int16_t> |
sequence<unsigned short> | std::vector<uint16_t> |
sequence<long> | std::vector<int32_t> |
sequence<unsigned long> | std::vector<uint32_t> |
sequence<long long> | std::vector<int64_t> |
sequence<unsigned long long> | std::vector<uint64_t> |
sequence<float> | std::vector<float> |
sequence<double> | std::vector<double> |
4、Maps
Fast DDS Gen支持与std::map容器等效的map。类型之间的等价性的处理方式与序列相同。
IDL | C++11 |
map<char, unsigned long long> | std::map<char, uint64_T> |
注意:Maps当前仅支持Primitive类型。
5、Structures
您可以使用一组具有多种类型的成员定义IDL结构。它将被转换为C++类,其中通过IDL定义的结构的成员映射到该类的私有数据成员。此外,还创建了set()和get()成员函数来访问这些私有数据成员。
以下IDL结构体定义:
struct Structure
{
octet octet_value;
long long_value;
string string_value;
};
将转换为:
{
public:
Structure();
~Structure();
Structure(const Structure &x);
Structure(Structure &&x);
Structure& operator=(const Structure &x);
Structure& operator=(Structure &&x);
void octet_value(uint8_t _octet_value);
uint8_t octet_value() const;
uint8_t& octet_value();
void long_value(int64_t _long_value);
int64_t long_value() const;
int64_t& long_value();
void string_value(const std::string
&_string_value);
void string_value(std::string &&_string_value);
const std::string& string_value() const;
std::string& string_value();
private:
uint8_t m_octet_value;
int64_t m_long_value;
std::string m_string_value;
};
结构可以继承其他结构,扩展其成员集。
struct ParentStruct
{
octet parent_member;
};
struct ChildStruct : ParentStruct
{
long child_member;
};
在这种情况下,生成的C++代码将是:
class ParentStruct
{
octet parent_member;
};
class ChildStruct : public ParentStruct
{
long child_member;
};
6、Unions
在IDL中,联合被定义为具有自己类型的成员序列,以及指定使用哪个成员的判别式。IDL联合类型被映射为C++类,具有访问联合成员和判别式的成员函数。
以下IDL联合体定义:
union Union switch(long)
{
case 1:
octet octet_value;
case 2:
long long_value;
case 3:
string string_value;
};
将转换为:
class Union
{
public:
Union();
~Union();
Union(const Union &x);
Union(Union &&x);
Union& operator=(const Union &x);
Union& operator=(Union &&x);
void d(int32_t __d);
int32_t _d() const;
int32_t& _d();
void octet_value(uint8_t _octet_value);
uint8_t octet_value() const;
uint8_t& octet_value();
void long_value(int64_t _long_value);
int64_t long_value() const;
int64_t& long_value();
void string_value(const std::string
&_string_value);
void string_value(std:: string &&_string_value);
const std::string& string_value() const;
std::string& string_value();
private:
int32_t m__d;
uint8_t m_octet_value;
int64_t m_long_value;
std::string m_string_value;
};
7、Bitsets(不对应std::bitset,使用难度较大)
位集是一种特殊的结构,它包含一组比特。位集最多可表示64位。每个成员都被定义为位字段,并简化了对位集某一部分的访问。
例如:
bitset MyBitset
{
bitfield<3> a;
bitfield<10> b;
bitfield<12, int> c;
};
MyBitset类型将存储总共25位(3+10+12),并且需要32位内存(存储位集大小的最低primitive type成员累积相加)。
位字段“a”允许我们访问前3位(0..2)。
位字段“b”允许我们访问下一个10位(3..12)。
位字段“c”允许我们访问下一个12位(13..24)。
生成的C++代码类似于:
class MyBitset
{
public:
void a(char _a);
char a() const;
void b(uint16_t _b);
uint16_t b() const;
void c(int32_t _c);
int32_t c() const;
private:
std::bitset<25> m_bitset;
};
在内部,它存储为std::bitset。对于每个位字段,get()和set()成员函数都使用较小的可能的原始无符号类型来访问它。在位字段“c”的情况下,用户已确定此访问类型将为int,因此生成的代码使用int32_t而不是自动使用uint16_t。
位集可以继承其他位集,扩展其成员集。
bitset ParentBitset
{
bitfield<3> parent_member;
};
bitset ChildBitset : ParentBitset
{
bitfield<10> child_member;
};
在这种情况下,生成的C++代码将是:
class ParentBitset
{
std::bitset<3> parent_member;
};
class ChildBitset : public ParentBitset
{
std::bitset<10> child_member;
};
注意,在这种情况下,ChildBitset将有两个std::bitset数据成员,一个属于ParentBitset,另一个属于ChildBitset。
8、Enumerations
IDL格式的枚举类型是具有关联数值的标识符的集合。IDL枚举类型直接映射到相应的C++11枚举定义。
以下为IDL枚举类型:
enum Enumeration
{
RED,
GREEN,
BLUE
};
将转换为:
enum Enumeration : uint32_t
{
RED,
GREEN,
BLUE
};
9、Bitmasks(对应std::bitset)
Bitmask是一种特殊的枚举,用于管理位掩码。它允许根据位掩码的位置定义位掩码。
以下IDL为位掩码类型:
@bit_bound(8)
bitmask MyBitMask
{
@position( 0) flag0,
@position( 1) flag1,
@position( 4) flag4,
@position( 6) flag6,
flag7
};
将转换为:
enum MyBitMask : uint8_t
{
flag0 = 0x01 << 0,
flag1 = 0x01 << 1,
flag4 = 0x01 << 4,
flag6 = 0x01 << 6,
flag7 = 0x01 << 7
};
注解bit_bound定义关联枚举的宽度。它必须是介于1和64之间的正数。如果省略,则为32位。对于每个标志,用户可以使用注释位置来定义标志的位置。如果省略,它将从上次定义的标志开始自动递增,从0开始。
10、Data types with a key
带键的数据类型用于定义单个主题上的数据子流。同一主题上具有相同键的数据值表示同一子流中的数据,而同一主题中具有不同键的数据表示不同子流中数据。中间件将这些子流保持分离,但所有子流都将被限制为主题的相同QoS值。如果未提供键成员,则与主题关联的数据集仅限于单个流。
为了使用键控主题,用户应该在结构中定义一些键成员。这是通过在用作键的结构成员之前编写@Key注释来实现的。例如,在以下IDL文件中,id和type字段将是带键数据类型:
struct MyType
{
@Key long id;
@Key string type;
long positionX;
long positionY;
};
Fast DDS Gen自动检测键控标记,并为TopicDataType(getKey())中的键生成函数正确地生成序列化方法,为Key 成员序列化大端字节序的128位MD5摘要。
注意:开源Fast DDS版本当前并未真正实现key的分流,静态类型key定义后,订阅者初始化时无法依据key来订阅,订阅者还是监听并接收到发布者发送的所有key的数据。静态类型对应的动态类型也没有key的分流定义,源码中也没有key分流的处理。在key示例程序实际测试中,也验证了该功能并未真正实现。
11、Aliases(类型别名容易造成混乱,不建议使用)
IDL 4.2允许对以下Primitive类型使用别名:
int8 |
uint8 |
int16 |
uint16 |
int32 |
uint32 |
int64 |
uint64 |
12、Annotations(注解)
注解不属于数据类型定义,它是应用程序允许用户定义和使用OMGIDL4.2规范中定义的注解。如果使用-TypeObject参数,则用户注解将传递给TypeObject生成的代码。
@annotation MyAnnotation
{
long value;
string name;
};
此外,以下标准注释是内置的(未实现的注解将识别并传递给TypeObject)。
Annotation | Implemented behavior |
@id | [Unimplemented] Assign a 32-bit integer identifier to an element. |
@autoid | [Unimplemented] Automatically allocate identifiers to the elements. |
@optional | [Unimplemented] Setting an element as optional. |
@extensibility | [Unimplemented] Applied to any element which is constructed. Allow specifying how the element is allowed to evolve. |
@final | [Unimplemented] Shortcut for @extensibility(FINAL) |
@appendable | [Unimplemented] Shortcut for @extensibility(APPENDABLE) |
@mutable | [Unimplemented] Shortcut for @extensibility(MUTABLE) |
@position | Setting a position to an element or group of elements. Used by bitmasks. |
@value | [Unimplemented] Allow setting a constant value to any element. |
@key | Alias for eProsima’s @Key annotation. Indicate that a data member is part of the key (please refer to Topics, keys and instances for more information). |
@must_understand | [Unimplemented] Indicate that the data member must be understood by any application making use of that piece of data. |
@default_literal | [Unimplemented] Allow selecting one member as the default within a collection. |
@default | Allow specifying the default value of the annotated element. |
@range | [Unimplemented] Allow specifying a range of allowed values for the annotated element. |
@min | [Unimplemented] Allow specifying a minimum value for the annotated element. |
@max | [Unimplemented] Allow specifying a maximum value for the annotated element. |
@unit | [Unimplemented] Allow specifying a unit of measurement for the annotated element. |
@bit_bound | Allow setting a size to a bitmasks. |
@external | [Unimplemented] Force the annotated element to be placed in a dedicated data space. |
@nested | [Unimplemented] Allow indicating that the objects from the type under annotation will always be nested within another one. |
@verbatim | [Unimplemented] Allow injecting some user-provided information into what the compiler will generate. |
@service | [Unimplemented] Allow indicating that an interface is to be treated as a service. |
@oneway | [Unimplemented] Allow indicating that an operation is one way only, meaning that related information flow will go from client to server but not back. |
@ami | [Unimplemented] Allow indicating that an interface or an operation is to be made callable asynchronously. |
@non_serialized | The annotated member will be omitted from serialization. |
大多数未实现[Unimplemented]的注解都与扩展类型相关。
13、Comments(注释)
这里有两种编写IDL注释的方法:
字符/*开始注释,注释以字符*/结束。
字符//开始一条注释,该注释终止于它们所在行的末尾。
/* MyStruct definition */
struct MyStruc
{
string mymessage; // mymessage data member.
};
有关IDL约定的更多信息,请参阅IDL 4.2规范。