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

pokxtpni  于 2023-01-03  发布在  其他
关注(0)|答案(6)|浏览(142)

我需要发送一些关于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];

是否有保存此类信息的标准方法?

a8jjtwal

a8jjtwal1#

我不明白你为什么不能用工会。这是标准的方式:

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中以零结尾的字符串。然后,您必须考虑根据需要分配和删除字符串数据的可能性。

4smxwvx5

4smxwvx52#

您可以使用boost::variant来实现这一点。

nfg76nw0

nfg76nw03#

有很多方法可以处理不同的数据类型。除了联合解决方案之外,您还可以使用如下通用结构:

typedef struct
{
    char m_type;
    void* m_data;
} 
structData;

这样你就知道了类型,你就可以把void* 指针转换成正确的类型。这就像联合解决方案,一种更像C而不是C的做事方式。C的方式是使用继承。你定义一个基类“Data”,使用继承来专门化数据。如果需要的话,你可以使用RTTI来检查类型。
但正如你所说,你需要通过VxWorks队列发送数据。我不是Maven,但如果这些队列是操作系统实时队列,所有以前的解决方案都不是好的。你的问题是,你的数据有可变长度(特别是字符串),你需要通过一个队列发送它们,可能会要求像固定长度的数据结构和这个数据结构的实际长度。
根据我的经验,正确的处理方法是将数据序列化为类似于缓冲区类/结构的东西,这样可以优化大小(只序列化需要的内容),并且可以通过队列发送缓冲区。
为了序列化,你可以使用像1字节的类型,然后数据。为了处理可变长度的数据,你可以使用1到n字节来编码数据长度,这样你就可以反序列化数据。
对于字符串:1字节编码类型(0x 01 =字符串,...)2字节编码字符串长度(如果需要小于65536字节)n数据字节
因此,字符串“Hello”将被序列化为:

0x00 0x00 0x07 0x65 0x48 0x6c 0x6c

你需要一个缓冲器类和一个序列化器/反序列化器类。然后你做一些类似的事情:

serialize data
send serialized data into queue

而在另一边

receive data
deserialize data

我希望这有帮助,而且我没有误解你的问题。如果VxWorks队列不是我想的那样,序列化部分就大材小用了。

yv5phkfx

yv5phkfx4#

要非常小心消息队列中的“string”成员,它是一个指针,指向包含实际字符串字符的malloc内存,所以你只是在队列中传递“指针”,而不是真实的的字符串。
接收进程可能无法访问字符串内存,或者更糟的是,在消息阅读器试图获取它时,它可能已经被破坏了。

7uhlpewt

7uhlpewt5#

+1为1800和Ylisar。
利用工会来处理这类事情可能是一条可行之路。但是,正如其他人所指出的,它有几个缺点:

  • 固有地易于出错。
  • 不能安全地伸展。
  • 无法使用构造函数处理成员(尽管可以使用指针)。

因此,除非您可以构建一个很好的 Package 器,否则使用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
flvtvl50

flvtvl506#

在Qt中尝试Qvariant

相关问题