我需要在VxWorks消息队列上发送一些信息。要发送的信息在运行时决定,并且可以是不同的数据类型。我正在使用这个结构 -
struct structData
{
char m_chType; // variable to indicate the data type - long, float or string
long m_lData; // variable to hold long value
float m_fData; // variable to hold float value
string m_strData; // variable to hold string value
};
我目前正在通过消息队列发送一个structData数组。
structData arrStruct[MAX_SIZE];
这里的问题是结构中只有一个变量一次有用,另外两个变量无用。因此,消息队列不必要地重载。 我不能使用联合,因为数据类型和值是必需的。 我尝试使用模板,但它没有解决问题。我一次只能发送一个数据类型的结构数组。
template <typename T>
struct structData
{
char m_chType;
T m_Data;
}
structData<int> arrStruct[MAX_SIZE];
是否有标准的方式来保存这些信息?
答案 0 :(得分:7)
我不明白为什么你不能使用工会。这是标准方式:
struct structData
{
char m_chType; // variable to indicate the data type - long, float or string
union
{
long m_lData; // variable to hold long value
float m_fData; // variable to hold float value
char *m_strData; // variable to hold string value
}
};
通常情况下,您打开数据类型,然后访问对该类型有效的字段。
请注意,您无法将string
放入联合,因为string
类型是非POD类型。我已将其更改为使用指针,该指针可以是C以零结尾的字符串。然后,您必须考虑根据需要分配和删除字符串数据的可能性。
答案 1 :(得分:6)
您可以使用boost::variant。
答案 2 :(得分:5)
有许多方法可以处理不同的数据类型。除了union解决方案,您还可以使用通用结构,如:
typedef struct
{
char m_type;
void* m_data;
}
structData;
这样您就知道了类型,并且可以将void *指针转换为正确的类型。 这就像联合解决方案更多C而不是C ++的做事方式。 C ++方式将是使用继承的东西。您可以定义基础“数据”类和使用继承来专门化数据。如果需要,您可以使用RTTI检查类型。
但正如您所说,您需要通过VxWork队列发送数据。我不是专家,但如果这些队列是OS实时队列,所有以前的解决方案都不是好的。您的问题是您的数据具有可变长度(特别是字符串),您需要通过队列发送它们,这可能会要求类似固定长度数据结构和此数据结构的实际长度。
根据我的经验,处理这个问题的正确方法是将数据序列化为缓冲类/结构。这样你可以优化大小(你只需序列化你需要的东西),你可以通过队列发送缓冲区。
要序列化,您可以使用类似1字节的类型,然后使用数据。要处理可变长度数据,可以使用1到n个字节来编码数据长度,这样就可以反序列化数据。
对于字符串: 1个字节来编码类型(0x01 = string,...) 2个字节来编码字符串长度(如果你需要少于65536字节) n个数据字节
因此字符串“Hello”将被序列化为:
0x00 0x00 0x07 0x65 0x48 0x6c 0x6c
您需要一个缓冲类和一个序列化/反序列化器类。然后你做了类似的事情:
serialize data
send serialized data into queue
在另一边
receive data
deserialize data
我希望它有所帮助,而且我没有误解你的问题。如果VxWorks队列不是我想的那样,那么序列化部分就太过分了......
答案 3 :(得分:2)
对邮件队列中的“string”成员要非常小心。在引擎盖下,它是指向包含实际字符串字符的某些malloc内存的指针,因此您只传递队列中的“指针”,而不是真正的字符串。
接收过程可能无法访问字符串内存,或者 - 在信息阅读器尝试获取时可能已经被破坏。
答案 4 :(得分:0)
1800和Ylisar的+1。
使用联合作为这种事情可能是要走的路。但是,正如其他人指出的那样,它有几个缺点:
因此,除非你能构建一个漂亮的包装器,否则使用boost :: variant方式可能更安全。
这有点偏离主题,但这个问题是为什么ML家族的语言具有如此强烈的吸引力(至少对我而言)的原因之一。例如,您的问题在OCaml中通过以下方式得到优雅解决:
(*
* LData, FData and StrData are constructors for this sum type,
* they can have any number of arguments
*)
type structData = LData of int | FData of float | StrData of string
(*
* the compiler automatically infers the function signature
* and checks the match exhaustiveness.
*)
let print x =
match x with
| LData(i) -> Printf.printf "%d\n" i
| FData(f) -> Printf.printf "%f\n" f
| StrData(s) -> Printf.printf "%s\n" s
答案 5 :(得分:0)
在Qt中尝试QVariant