Разыменование структуры объединения структур - PullRequest
2 голосов
/ 09 февраля 2012
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;

Теперь я делаю сообщение и передаю указатель на это сообщение функции. Внутри этой функции мне нужно удалить ссылку на сообщение и извлечь из него необходимые данные.

Эти данные будут зависеть от того, был ли пакет заполнен данными типа packetType1 или типа packetType2. Внутри сообщения целочисленный тип переменной может содержать только значение 1 или 2, сообщая, что пакет внутри сообщения имеет тип packetType1 или тип packetType2.

Я хочу знать, безопасно ли это делать -

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

}

Редактировать: (Для всех тех, кто спрашивает, почему я использовал void *)

Эти сообщения отправляются от одного процесса другому, используя очередь сообщений posix, а затем декодируются там. Проблема в том, что даже эта структура сообщения может быть другой. Единственное, в чем я уверен, так это то, что переменная типа int всегда будет рядом, чтобы направлять меня. Другая часть сообщения может измениться. Поэтому мне пришлось сделать эту функцию общей, приняв void *, а затем выполнить внутреннее декодирование, используя значение, предоставленное типом переменной.

Считайте, что кто-то сейчас делает подобное сообщение -

struct
{
    int type;

    float data;
    bool moreData;
    int evenMoreData;

} newMessage;

Для этого нового сообщения было решено, что значение для типа переменной всегда будет 3.

Так что в моей функции еды я просто добавлю еще одно предложение, как это

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

Будет ли это по-прежнему безопасно? Надеюсь, теперь это имеет смысл?

Ответы [ 3 ]

3 голосов
/ 09 февраля 2012

выглядит хорошо, но я бы переписал eatPacket() так:

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

}

Нет никакой необходимости в гимнастике void*, которую я вижу. Если вам действительно нужно, чтобы msg был указателем, вы можете изменить вышеуказанное простым способом (-> для . и т. Д.).

1 голос
/ 11 февраля 2012

Я бы этого не делал. Я думаю, что было бы намного чище создать абстрактный класс BaseMessage, а затем получить класс для полезной нагрузки int и один для полезной нагрузки bool. Тогда у вас может быть виртуальный метод GetData (). Когда вы передаете указатель на базовый класс, корректная виртуальная функция будет вызвана для возврата ваших данных. Объединение - это почти всегда запах кода, с которым могут помочь методы ОО. Многое из того, как я на самом деле это реализую, зависит от разнообразия сообщений и того, как они в конечном итоге привыкнут, но, надеюсь, вы поймете идею.

1 голос
/ 09 февраля 2012

Что бы я сделал?

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

}

Безопасно ли идти по твоему пути?Я действительно не знаю.Что такое сообщение?

...