在单个结构中处理不同的数据类型

时间:2009-07-09 09:42:28

标签: c++

我需要在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];

是否有标准的方式来保存这些信息?

6 个答案:

答案 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