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 ...