Byte Order and Endianness

Handling Structs and Endianness

What's the best way to handle endianness when working with structs that contain multiple different-sized members?

Abstract art representing computer programming

When working with structs containing multiple members of different sizes, we need to handle each member's endianness individually. Here's a structured approach to handling this common scenario:

Basic Approach

First, let's look at a simple struct and how to properly serialize it:

#include <iostream>
#include "SDL.h"

struct PlayerData {
  Uint16 Level;
  Uint32 Experience;
  float Health;
};

void WritePlayerData(SDL_RWops* Handle,
                     const PlayerData& Data) {
  SDL_WriteLE16(Handle, Data.Level); 
  SDL_WriteLE32(Handle, Data.Experience); 
  SDL_WriteLE32(Handle, Data.Health);      
}

PlayerData ReadPlayerData(SDL_RWops* Handle) {
  PlayerData Data;
  Data.Level = SDL_ReadLE16(Handle); 
  Data.Experience = SDL_ReadLE32(Handle); 
  Data.Health = SDL_ReadLE32(Handle);      
  return Data;
}

int main() {
  // Create test data
  PlayerData TestData{
    .Level = 42,
    .Experience = 1000000,
    .Health = 98.5f
  };

  // Write to file
  SDL_RWops* WriteHandle{
    SDL_RWFromFile("player.dat", "wb")};
  if (WriteHandle) {
    WritePlayerData(WriteHandle, TestData);
    SDL_RWclose(WriteHandle);
  }

  // Read and verify
  SDL_RWops* ReadHandle{
    SDL_RWFromFile("player.dat", "rb")};
  if (ReadHandle) {
    PlayerData LoadedData{
      ReadPlayerData(ReadHandle)};
    SDL_RWclose(ReadHandle);

    std::cout << "Level: " << LoadedData.Level
      << "\nExp: " << LoadedData.Experience
      << "\nHealth: " << LoadedData.Health
      << '\n';
  }
}
Level: 42
Exp: 1000000
Health: 98.5

Advanced Techniques

For more complex structs, you might want to create a serialization helper class:

#include <iostream>
#include "SDL.h"

class BinaryWriter {
  SDL_RWops* Handle;

public:
  explicit
    BinaryWriter(SDL_RWops* Handle)
    : Handle{Handle} {}

  void Write(Uint16 Value) {
    SDL_WriteLE16(Handle, Value);
  }

  void Write(Uint32 Value) {
    SDL_WriteLE32(Handle, Value);
  }

  void Write(float Value) {
    SDL_WriteLE32(Handle, Value);
  }
};

struct PlayerData {
  Uint16 Level;
  Uint32 Experience;
  float Health;

  void Serialize(BinaryWriter& Writer) {
    Writer.Write(Level);
    Writer.Write(Experience);
    Writer.Write(Health);
  }
};

int main() {
  PlayerData Data{
    .Level = 42,
    .Experience = 1000000,
    .Health = 98.5f
  };

  SDL_RWops* Handle{
    SDL_RWFromFile("player.dat", "wb")};
  if (Handle) {
    BinaryWriter Writer{Handle};
    Data.Serialize(Writer); 
    SDL_RWclose(Handle);
  }
}

Key points to remember:

  • Always handle each member individually with the appropriate endianness function
  • Keep track of the order of serialization to match when deserializing
  • Consider padding and alignment in your structs
  • Use helper classes to make the code more maintainable
  • Document your serialization format for future maintenance

Answers to questions are automatically generated and may not have been reviewed.

sdl2-promo.jpg
Part of the course:

Game Dev with SDL2

Learn C++ and SDL development by creating hands on, practical projects inspired by classic retro games

Free, unlimited access

This course includes:

  • 75 Lessons
  • 100+ Code Samples
  • 91% Positive Reviews
  • Regularly Updated
  • Help and FAQ
Free, Unlimited Access

Professional C++

Comprehensive course covering advanced concepts, and how to use them on large-scale projects.

Screenshot from Warhammer: Total War
Screenshot from Tomb Raider
Screenshot from Jedi: Fallen Order
Contact|Privacy Policy|Terms of Use
Copyright © 2025 - All Rights Reserved