Processing of various data types in a single structure

I need to send some information to the VxWorks message queue. The information to be sent is determined at runtime and can have different types of data. I use a structure for this -

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 }; 

I am currently sending an array of structData to a message queue.

 structData arrStruct[MAX_SIZE]; 

The problem is that only one variable in the structure is useful at a time, the other two are useless. Therefore, the message queue is not overloaded. I cannot use joins because the data type and value are required. I tried using templates, but this does not solve the problem. I can send an array of structures of only one data type at a time.

 template <typename T> struct structData { char m_chType; T m_Data; } structData<int> arrStruct[MAX_SIZE]; 

Is there a standard way to store such information?

+4
c ++
source share
6 answers

There are many ways to handle different types of data. In addition to the union solution, you can use a common structure, for example:

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

That way, you know the type, and you can cast the void * pointer to the type you want. This seems like an allied solution to more than C than to C ++. A C ++ path would be something using inheritance. You define the base class Data as inheritance of use for specializing data. You can use RTTI for type checking if necessary.

But, as you said, you need to send your data to the VxWork queue. I am not an expert, but if these queues are the real-time OS queue, all the previous solutions are not good. Your problem is that your data has a variable length (in particular a string), and you need to send it through a queue, which will probably require something like a fixed data size and the actual length of this document.

In my experience, the right way to handle this is to serialize the data into something like a class / struct buffer. This way you can optimize the size (you only serialize what you need), and you can send your buffer through the queue.

For serialization, you can use something like 1 byte for the data type. To process data of variable length, you can use from 1 to n bytes to encode the length of the data so that you can deserialize the data.

For a string: 1 byte for encoding of the type (0x01 = string, ...) 2 bytes for encoding the length of the string (if you need less than 65536 bytes) n bytes of data

So, the string "Hello" will be serialized as:

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

You need a buffer class and a serializer / deserializer class. Then you do something like:

 serialize data send serialized data into queue 

and on the other hand

 receive data deserialize data 

I hope this helps, and I did not get your problem wrong. Serialization is partly overpriced if VxWorks queues are not what I think ...

+5
source share

I do not understand why you cannot use the union. This is the standard way:

 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 } }; 

Usually you include a data type, and then you access a field that is valid for that type.

Note that you cannot put a string in a union because the type of string is a non-POD type. I modified it to use a pointer, which can be a null-character string. Then you should consider highlighting and deleting string data as needed.

+7
source share

You can use boost :: variant for this.

+6
source share

Be very careful with the string member in the message queue. Under the hood, this is a pointer to some malloc'd memory that contains the actual string characters, so you only pass the β€œpointer” in your queue, not the actual string.

The retrieval process may not potentially have access to string memory, or -worse β€” it may already be destroyed by the time your message reader tries to retrieve it.

+2
source share

+1 for 1800 and Ylisar.

Using union for this kind of thing is probably the way to go. But, as others have pointed out, it has several drawbacks:

  • inherent in errors.
  • not securely extensible.
  • cannot handle elements with constructors (although you can use pointers).

So, if you cannot create a beautiful wrapper, the boost :: variant transition will probably be more secure.


This is a bit offtopic, but this question is one of the reasons why ML languages ​​have such a strong appeal (at least for me). For example, your problem is elegantly resolved in OCaml with:

 (* * 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 
0
source share

Try QVariant in Qt

0
source share

All Articles