Estou escrevendo um serializador binário simples paragere arquivos salvos para um videogame de 64 bits voltado para plataformas de 64 bits do Windows, Mac e Linux. Os tipos de variáveis selecionados para serialização são: char, short, bool, int não assinado, int, float, possivelmente duplo e possivelmente longo int. Estou compilando no Visual Studio. A serialização é o mais simples possível, sem verificações, apenas gravação simples dos dados binários e desserialização dos dados na mesma ordem. O jogo salva novos dados no arquivo com muita frequência durante o jogo, mas os dados são desserializados apenas uma vez, pouco antes do jogo.
Eu não achava que portabilidade fosse algoque eu precisava me preocupar com uma função simples de salvar jogo; no entanto, tenho lido sobre os muitos problemas de portabilidade associados à serialização binária (por exemplo, representação de ponto flutuante, variações na largura de bit de ints, endianness, alinhamento etc.) e não tenho confiança suficiente na minha compreensão do assunto para ter certeza que esses problemas de portabilidade não irão elevar sua cabeça neste projeto. Talvez alguém tenha a gentileza de compartilhar alguma perspectiva sobre as seguintes suposições:
- As variáveis podem ser serializadas para um binário em uma máquina e o O binário pode então ser copiado e desserializado com segurança em um máquina diferente com o mesmo sistema operacional e uma CPU x86-64.
- Se eu assumir que todas as máquinas executando ojogo são CPUs estilo x86-64 little-endian que executam sistemas operacionais de 64 bits, posso assumir que o arquivo binário pode ser totalmente portátil entre sistemas operacionais também?
- Se eu expandir o desenvolvimento para apoiar umVersão de 32 bits do jogo (ainda assumindo uma arquitetura de CPU x86-64 no destino plataforma, mas SO de 32 bits) e um usuário final de SO de 32 bits decide atualizar para um sistema operacional de 64 bits, instala a versão de 64 bits do jogo e então carrega o antigo arquivo salvo, que foi serializado no 32-bit SO executando a versão de 32 bits do jogo - esses tipos de variáveis em seguida, seja desserializado com segurança na plataforma de 64 bits na ordem em que foram serializados sem nenhuma verificação ou teste para compatibilidade?
É possível que salvar em uma máquina e carregar em outra possa corromper os dados em qualquer um desses cenários?
Muito obrigado antecipadamente.
Respostas:
1 para resposta № 1Se você usar tipos inteiros de tamanho, como ::std::uint32_t
em vez de tipos obscuros, como unsigned long
então você será praticamente salvo do inteirovariações de tamanho que podem ocorrer entre plataformas de 32 bits / 64 bits e diferentes compiladores. A largura de bit inteira tecnicamente pode variar, mas apenas em plataformas exóticas que definitivamente não podem ser consideradas adequadas para jogos. O tamanho e a representação do ponto flutuante também não devem ser uma preocupação.
Para garantir que o tamanho e o alinhamento das estruturas de dados que estão sendo lidas / gravadas permaneçam consistentes nas plataformas, você deve usar static_assert
no seu código.
No entanto, verificar endianness é obrigatório se vocêdeseja que seus arquivos salvos sejam portáteis. Normalmente, você pode querer serializar dados usando endianness nativo e escrever algum número mágico no início do arquivo indicando sua endianness (como 0x01020304
) Então, quando você desserializa, primeiro verifica essa mágica e seleciona o desserializador de endianness nativo (que é mais rápido) ou o desserializador de endianness invertido (que é mais lento).