简体   繁体   中英

De-referencing structure of union of structures

typedef struct
{
    int data1;
    float data2;
} packetType1;

typedef struct
{
     bool data1;
} packetType2;

typedef union
{
     packetType1 p1;
     packetType2 p2;
} packet;

struct
{
    int type;
    packet myPacket;
} message;

Now I make a message and pass the pointer to this message to a function. Inside this function I need to de-reference the message and take out the necessary data from it.

This data will depend on whether packet was filled with data of packetType1 type or of packetType2 type. Inside message , the integer variable type can contain the value 1 or 2 only, telling that packet inside message is of type packetType1 or of type packetType2.

I want to know if this is safe to do -

packetType1 s1;
s1.data1 = 10;
s1.data2 = 22.22;


packetType2 s2;
s2.data1 = true; 

packet pack1; 
pack1.p1 = s1;

packet pack2;
pack2.p2 = s2;

message m1;
m1.type = 1;
m1.myPacket = pack1;

message m2;
m2.type = 2;
m2.myPacket = pack2;

eatPacket( &m1 );
eatPacket( &m2 );

void eatPacket( void *p )
{

    if( *(int*)p == 1)
    {
       message msg = *(message*)p
       cout << msg.myPacket.data1;
       cout << msg.myPacket.data2;
    }

    else if( *(int*)p == 2)
    {
       message msg = *(message*)p
       cout << msg.myPacket.data1;           
    }

}

Edit: ( For all those who are asking why I had used void* )

These messages are sent from one process to other using posix message queue and then decoded there. Problem is that even this message structure could be different. Only thing I am sure is that the variable int type will always be there to guide me. Other part of the message might change. So I had to make this function generic by making it accept a void * and then do decoding internally using the value provided by variable type.

Consider that someone makes a message like this now-

struct
{
    int type;

    float data;
    bool moreData;
    int evenMoreData;

} newMessage;

For this new message it was decided that value for variable type would always be 3.

So in my eat function I will just add another clause like this

if( *(int*)p == 3)
{
       newMessage msg = *(newMessage*)p
       cout << msg.data;
       cout << msg.moreData;
       cout << msg.evenMoreData;
}

Will it still be safe to do so ? I hope this makes sense now ?

It looks fine, but I'd rewrite eatPacket() like this:

void eatPacket(const message& msg)
{

    if(msg.type == 1)
    {
       cout << msg.myPacket.data1;
       cout << msg.myPacket.data2;
    }

    else if(msg.type == 2)
    {
       cout << msg.myPacket.data1;           
    }

}

There's really no need for the void* gymnastics that I can see. If you really need msg to be a pointer you can modify the above in a straightforward way ( -> for . , etc).

What would I do?

void eatPacket( message* msg )
{
    if(NULL == msg) return;

    if( message->type == 1 )
    {
       cout << msg->myPacket.data1;
       cout << msg->myPacket.data2;
    }
    else if(message->type == 2 )
    {
       cout << msg->myPacket.data1;           
    }

}

Is it safe to do your way? I don't really know. What is message?

I wouldn't do any of this. I would think it would be much cleaner to create an abstract BaseMessage class and then derive a class for the int payload and one for the bool payload. Then you could have a virtual GetData() method. When you pass in the pointer to the base class the correct virtual function will get invoked to return your data. A union is almost always a code smell that OO techniques can help with. A lot of how I would actually implement this depends on the variety of messages and how they eventually get used but hopefully you get the idea.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM