Dica número 1: se estiver muito complicado, sugiro rodar o seguinte programa (corrija eventuais erros de compilação que ocorrerem, só testei com MS Visual Studio 2005)
#include <stdio.h>
#include <string.h>
#include <stddef.h>
typedef struct _tagPACOTE_RESPOSTA {
_int32 tipo;
_int64 valorInt;
double valorDouble;
} PACOTE_RESPOSTA;
typedef union _UNION {
PACOTE_RESPOSTA pr;
unsigned char by [32];
} UNION;
void dump (unsigned char by[], int len) {
int i;
for (i = 0; i < len; ++i) { printf ("%02X ", by[i] & 0xFF); }
}
int main (int argc, char *argv[]) {
UNION u;
memset (u.by, 0, sizeof (u.by));
printf ("Offset Of tipo = %d\n", offsetof(UNION, pr.tipo));
u.pr.tipo = 0x12345678;
printf ("Offset Of valorInt = %d\n", offsetof(UNION, pr.valorInt));
u.pr.valorInt = 0x0123456789ABCDEFLL;
printf ("Offset Of valorDouble = %d\n", offsetof(UNION, pr.valorDouble));
u.pr.valorDouble = 3.1415926535897932;
printf ("Sizeof PACOTE_RESPOSTA = %d\n", sizeof(PACOTE_RESPOSTA));
dump (u.by, sizeof(u.by));
}
Rodando esse programa usando o Microsoft Visual Studio 2005 gerando código para Win32, ele gerou a seguinte resposta:
Offset Of tipo = 0
Offset Of valorInt = 8
Offset Of valorDouble = 16
Sizeof PACOTE_RESPOSTA = 24
78 56 34 12 00 00 00 00 EF CD AB 89 67 45 23 01 18 2D 44 54 FB 21 09 40 00 00 00 00 00 00 00 00
O que ele me diz?
- Mesmo um _int32 ocupando 4 bytes, ele acabou ocupando 8 bytes na struct, porque há um conceito de “alignment” ou “packing” que faz com que uma variável ‘int’ ou ‘__int64’ ocupe um endereço múltiplo de 8.
- Os bytes são armazenados ao contrário (em máquinas Intel ou AMD). Você viu que o número 0x12345678 foi armazenado como 78 56 34 12 e o númer 0x0123456789ABCDEF foi armazenado como EF CD AB 89 67 45 23 01
- Embora não seja trivial enxergar isso, um double ocupa 8 bytes e também é armazenado ao contrário.
Portanto, você precisaria pegar os bytes (usando um DataInputStream acoplado a um SocketInputStream, quem sabe) e então “desinverter” os bytes para podermos ter os dados desejados.
Para converter 8 bytes em um double, é necessário converter esses 8 bytes para um long, e então usar o método Double.longBitsToDouble.
Em outras arquiteturas, o programa pode compilar e dar resultados diferentes. Diga o que ocorre para seu compilador e sistema operacional (talvez precise acertar algumas coisas, como _int32 ou __int32, _int64 ou __int64.)