Understanding Byte Alignment in C and C++

Byte Alignment Definition

Byte alignment is a memory layout rule in computer programming where the starting address of data in memory must be a multiple of its own size.

One can imagine memory as a series of contiguous small boxes, each of size 1 byte, with each box having a unique address starting from 0:

Address: 0 1 2 3 4 5 6 7 ...

A char type occupies 1 byte and can be placed at any address (addresses are multiples of 1).

A short type occupies 2 bytes and must be placed at addresses 0, 2, 4, … (addresses are multiples of 2).

An int type occupies 4 bytes and must be placed at addresses 0, 4, 8, … (addresses are multiples of 4).

A long long type occupies 8 bytes and must be placed at addresses 0, 8, 16, … (addresses are multiples of 8).

If the starting address of the data does not comply with this rule, it is referred to as unaligned.

Why is Byte Alignment Necessary?

Why do computers have such rules? The main reasons are twofold:

Performance Optimization (the main reason)

When a CPU reads memory, it does not read one byte at a time but rather reads in blocks. The size of this block is typically the CPU’s word size, for example, a 32-bit CPU has a block size of 4 bytes, while a 64-bit CPU has a block size of 8 bytes.

Aligned Case

Assuming we want to read a 4-byte int located at address 4, the CPU can read the complete block from addresses 4, 5, 6, and 7 into the register at once, which is very efficient.

Unaligned Case

Assuming this int is located at address 5, the CPU needs to first read the block from addresses 4-7, then read the block from addresses 8-11, and finally extract and combine the 4 bytes of data from these two blocks to obtain the complete int value. This clearly requires more CPU cycles, resulting in lower performance.

Hardware Limitations

Some hardware platforms (especially certain embedded systems or older CPUs) do not support accessing unaligned memory addresses. Forcing access can lead to hardware exceptions or cause the program to crash. Even modern x86/x86_64 architecture CPUs that support unaligned access will experience significant performance penalties.

Byte Alignment Rules

Intrinsic Alignment Values of Basic Data Types

For basic data types in C/C++, their intrinsic alignment value is typically equal to their sizeof size. The memory alignment values for basic types are as follows:

char: sizeof=1, alignment value = 1

short: sizeof=2, alignment value = 2

int: sizeof=4, alignment value = 4

long: sizeof=4 (32-bit system) or 8 (64-bit system), alignment value = 4 or 8

long long: sizeof=8, alignment value = 8

float: sizeof=4, alignment value = 4

double: sizeof=8, alignment value = 8

pointer: sizeof=4 (32-bit system) or 8 (64-bit system), alignment value = 4 or 8

Overall Alignment Rules for Structures

The total size of a structure must be a multiple of the largest alignment value of its internal members; this is to ensure that when the structure is a member of another structure, it also meets alignment requirements.

Alignment Rules for Structure Members

Each member in a structure must have its starting address as a multiple of its own alignment value. If the ending address of the previous member does not satisfy the alignment requirement of the current member, the compiler will insert padding bytes in between to adjust the address.

Example One

struct Example
{
    char a;   // 1 byte
    short b; // 2 bytes
    int c;      // 4 bytes
};

char a is placed at address 0.

short b has an alignment value of 2, so its starting address must be a multiple of 2; the previous member a occupies 1 byte at address 0, making the next available address 1; since address 1 is not a multiple of 2, the compiler will insert 1 byte of padding between a and b, placing b at address 2.

int c has an alignment value of 4, so its starting address must be a multiple of 4; the previous member b occupies 2 bytes at address 2, ending at address 3; the next available address is 4, which is a multiple of 4, so c is placed at address 4.

Total bytes occupied by structure members: 1 (a) + 1 (Padding) + 2 (b) + 4 (c) = 8 bytes.

The maximum alignment value of the structure is 4 (from int), and since 8 is a multiple of 4, the total size of the structure in this example is 8 bytes.

Example Two

struct Example
{
    char a;  // 1 byte
    int c;      // 4 bytes
    short b;  // 2 bytes
};

char a is placed at address 0.

int c has an alignment value of 4, so its starting address must be a multiple of 4; 3 bytes of padding are needed after a, placing c at address 4.

short b has an alignment value of 2; the previous member c occupies 4 bytes at address 4, ending at address 7. The next available address is 8, which is a multiple of 2, so b is placed at address 8.

Total bytes occupied by structure members: 1 (a) + 3 (Padding) + 4 (c) + 2 (b) = 10 bytes.

The maximum alignment value of the structure is 4 (from int), and since 10 is not a multiple of 4, 2 bytes of padding are needed at the end, making the total size of the structure in this example 12 bytes (12 is a multiple of 4).

Comparing Example One and Example Two, it can be observed that: the order of member declarations affects the total size of the structure. To save memory, it is generally recommended to place smaller members first and larger ones later, while also considering readability.

How to Control Byte Alignment

In certain cases, such as when dealing with specific memory layouts for hardware devices or network protocols, or to save memory, we may need to manually change the compiler’s default alignment rules.

In C/C++, the compiler directive #pragma pack can be used to achieve this, as follows:

#pragma pack(n): sets the current alignment value to n, where n must be a power of 2 (1, 2, 4, 8, 16, etc.).

#pragma pack(): restores the default alignment.

Example

#pragma pack(1) // Set alignment value to 1, i.e., align by 1 byte

struct PackedStruct
{
char a;
int b;
short c;
};
#pragma pack() // Restore default alignment

// With 1-byte alignment, there is no padding between structure members
// Total size = 1 + 4 + 2 = 7 bytes

#pragma pack is a powerful tool, but it is also a double-edged sword. Using it may compromise code portability and introduce performance issues, so it must be used with caution.

Conclusion

The purpose of byte alignment is to enhance CPU access performance to memory and to meet the requirements of certain hardware platforms.

The core idea: the starting address of data must be a multiple of its own size (or specified alignment value).

Structure alignment: members are arranged according to their own alignment values, with possible padding in between, and the total size of the structure is a multiple of the maximum member alignment value.

Manual control: compiler directives like #pragma pack can be used to change default alignment behavior, but should be used cautiously.

This article introduces the concept of memory alignment and the rules of memory alignment. Correctly understanding byte alignment rules is crucial for writing efficient and portable low-level code (such as embedded development, driver development, and network communication message encapsulation). If you like it, please give it a follow!

Author’s Note: Thank you to all the friends who took the time to read my article. All articles on this public account are the result of my efforts to organize my knowledge system in my spare time. I chose to publish on this platform to create a home for my knowledge for easy reference and to help those who are new to programming. The C/C++ series of articles is a starting point, not an endpoint. In the future, I will also organize and share on topics like “Go”, “Design Patterns”, “Distributed System Design Architecture”, and “Open Source Project Code Analysis”. If you are interested, please follow me, and we can learn and exchange ideas together. Regarding the update frequency, since I write articles in my spare time, I cannot guarantee daily updates, but I will try to update at least once a week. If you wish to communicate with the author online, you can scan the code to add me as a friend: Understanding Byte Alignment in C and C++Book Recommendation: Although this is an advertisement, I have principles and will not recommend random things that I find annoying myself. I recommend this excellent book, “Domain-Driven Design”, which is the best book I have read on architectural design. Although the content is somewhat challenging, if you are interested in architectural design, I strongly recommend that you study it carefully.

Leave a Comment