Союзы сложны. В течение многих лет я не мог их понять, затем я начал делать что-то с сетевыми протоколами, и кто-то показал мне свет. Скажем, у вас есть заголовок, а затем после заголовка есть различные типы пакетов, например:
| тип (4 байта) | UID (8 байт) | длина полезной нагрузки (2 байта) | Полезная нагрузка (переменная длина) |
А потом были бы различные типы полезных нагрузок пакета ... Ради аргумента, могли бы быть привет, до свидания, и пакеты сообщения ...
Ну, вы можете создать вложенный набор структур / объединений, которые могут точно представлять пакет в этом протоколе, например ...
struct packet {
uint type;
char unique_id [8];
ushort payload_length;
union payload {
struct hello {
ushort version;
uint status;
};
struct goodbye {
char reason[20];
uint status;
};
struct message {
char message[100];
};
};
};
Неизбежно, вы получаете этот протокол из операционной системы через вызов read (), и это всего лишь набор байтов. Но если вы осторожны с определением структуры, и все типы имеют правильный размер, вы можете просто сделать указатель на структуру, указать ее в буфере, заполненном случайными данными, и ...
char buf[100];
packet *pkt;
read(outsideworld,&buf,1000);
pkt = (struct packet *)&buf;
и читать ваши пакеты так же просто, как ...
switch(pkt->type){
case PACKET_MESSAGE:
printf("message = %s\n",
pkt->payload.message.message);
break;
case PACKET_HELLO:
printf("hello! version = %d status = %d\n",
pkt->payload.hello.version,
pkt->payload.hello.status);
break;
case PACKET_GOODBYE:
printf("goodbye! reason = %s status = %d\n",
pkt->payload.goodbye.reason,
pkt->payload.goodbye.status);
break;
}
Никаких обходов, подсчета байтов и т. Д. Вы можете вкладывать это так глубоко, как хотите (создайте объединение для IP-адресов, которое дает вам целые данные в виде целого числа без знака или отдельных байтов, чтобы было проще выведите из него 192.168.0.1).
Профсоюзы не замедляют ваш код, потому что все это просто переводится в машинные коды в смещения.