Structure Packing

Members are laid out in the memory in the exact order, they are declared (unless pragma packed is used)

  • char data types can be put anywhere in the memory
  • short data type must start at memory location divisible by 2
  • int data type must start at memory location divisible by 4
  • long long data type must start at memory location divisible by 8

Consider this peice of code

struct emp {
    char c; // 1
    int  x; // 4
    char d; // 1
};
 
struct emp_with_padding {
    char c; // 1
    char pad[3];
    int  x; // 4
    char d; // 1
    char pad[3];
};
 
struct emp_reordered {
    int  x;
    char c;
    char d;
};
 
#pragma pack(1)
struct emp_pragma_packed {
    int  x;
    char c;
    char d;
};
 
struct emp_packed {
    int  x;
    char c;
    char d;
}__attribute__((__packed__));
 
 
int main() {
    std::cout << sizeof(emp) << std::endl; // 12
    std::cout << sizeof(emp_with_padding) << std::endl; // 12
    std::cout << sizeof(emp_reordered) << std::endl; // 8
    std::cout << sizeof(emp_pragma_packed) << std::endl; // 6
    std::cout << sizeof(emp_packed) << std::endl; // 6
    return 0;
}

GCC does not do structure reordering on itself because the structure might be sent and recieved over network.

#include <iostream>
 
struct Order {
    int  qty;
    int  prc;
    char side;      // buy or sell
    char symbol[6]; // ticker symbol name
};
static_assert(sizeof(Order) == 16);
 
int main() {
    Order order{ 12, 100, 'B', "GOOGL" };
    auto orderStr = reinterpret_cast<char*>(&order);
 
    // send this orderStr as an array of bytes 
    // on the wire to other trading server
    
    // other side will unpack it like this
    auto recvd_order = reinterpret_cast<Order*>(orderStr);
 
    std::cout << "qty = " << recvd_order->qty << std::endl;
    std::cout << "prc = " << recvd_order->prc << std::endl;
    std::cout << "side = " << recvd_order->side << std::endl;
    std::cout << "symbol = " << recvd_order->symbol << std::endl;
}

References