Alignment issues in c++

Alignment issues in c++

Reasons for alignment

Although memory is measured in bytes, most processors do not access memory in byte blocks. It generally accesses memory in units of double bytes, four bytes, 8 bytes, 16 bytes or even 32 bytes. To access memory in units, we call these access units memory access granularity.

Now consider a processor with a 4-byte access granularity that takes an int type variable (32-bit system). The processor can only read data from the memory with an address that is a multiple of 4.

If there is no memory alignment mechanism, data can be stored arbitrarily. Now an int variable is stored in the associated four-byte address starting from address 1. When the processor retrieves the data, it must first read the first 4 from address 0. Byte block, remove the unwanted bytes (address 0), then read the next 4-byte block starting from address 4, also remove the unwanted data (address 5, 6, 7), leaving the last two blocks of data Merge into registers. This requires a lot of work.

bg1

Alignment rules

Valid alignment value: is the smaller of #pragma pack(n) and the length of the longest data type in the structure. Valid alignment values ​​are also called alignment units.

Note: n in
#pragma pack(n) can take any value among (1, 2, 4, 8, 16).

2) Rules:

  • The first address of a structure variable is an integer multiple of the effective alignment value (alignment unit).

  • The offset (offset) of the first member of the structure is 0. The offset of each subsequent member relative to the first address of the structure is an integer multiple of the smaller of the member size and the effective alignment value. If necessary, the compiler Padding bytes are added between members.

  • The total size of the structure is an integral multiple of the effective alignment value, and the compiler adds padding bytes after the last member if necessary.

  • Consecutive elements of the same type in a structure will be in continuous space, just like arrays.

Using the above rules, the following calculations are done through practical examples.

Example 1:

#include <iostream>

struct MyStruct {
    
    
    char c;
    int i;
    short s;
};

int main()
{
    
    
    MyStruct obj;
    std::cout << "start addr of obj = " << (void*)&obj << std::endl;
    std::cout << "offset of c = "  << offsetof(MyStruct,c) << std::endl;
    std::cout << "offset of i = " << offsetof(MyStruct,i) << std::endl;
    std::cout << "offset of s = " << offsetof(MyStruct,s) << std::endl;
    std::cout << "sizeof MyStruct = " << sizeof(MyStruct);
}

The execution results are as follows:

start of obj = 0x7fff2e8d1e94
offset of c = 0
offset of i = 4
offset of s = 8
sizeof MyStruct = 12

The longest data type in the structure is int, also with a length of 4. Therefore the effective alignment value of the structure is 4.

For the c variable, there is no suspense, it will be ranked at the 0 offset address.

For variable i, the type is int and the length is 4. The minimum value of int and valid alignment value is 4, so i needs to be arranged on an integer multiple of 4, so the first offset that meets the requirements is 4.

For variable s, the type is short, the length is 2, the minimum value of short and the valid alignment value is 2, and the first address that meets the requirements is 8.

So far, the space size used is 10, and the structure size needs to be an integer multiple of the effective alignment value, so 2 padding is needed, so the final size of the structure is 12.

MyStructDistribution

Example 2:

#include <iostream>
#pragma pack(2)
struct MyStruct {
    
    
    char c;
    int i;
    short s;
};

int main()
{
    
    
    MyStruct obj;
    std::cout << "start addr of obj = " << (void*)&obj << std::endl;
    std::cout << "offset of c = "  << offsetof(MyStruct,c) << std::endl;
    std::cout << "offset of i = " << offsetof(MyStruct,i) << std::endl;
    std::cout << "offset of s = " << offsetof(MyStruct,s) << std::endl;
    std::cout << "sizeof MyStruct = " << sizeof(MyStruct);
}

The execution results are as follows:

start addr of obj = 0x7fff488e3418
offset of c = 0
offset of i = 2
offset of s = 6
sizeof MyStruct = 8

First of all#pragma pack sets the alignment value to 2, the longest data type in the structure is int, and the length is also 4. Therefore the effective alignment value of the structure is 2.

For the c variable, there is no suspense, it will be ranked at the 0 offset address.

For variable i, the type is int and the length is 4. The minimum value of int and valid alignment value is 2, so i needs to be arranged on an integer multiple of 2, so the first offset that meets the requirements is 2.

For variable s, the type is short, the length is 2, the minimum value of short and the valid alignment value is 2, and the first address that meets the requirements is 6.

So far, the space size used is 8, which has met the requirement that the structure size be an integer multiple of the effective alignment value.

MyStruct distribution 2

#include <iostream>
#pragma pack(1)
struct MyStruct {
    
    
    char c;
    int i;
    short s;
};

int main()
{
    
    
    MyStruct obj;
    std::cout << "start addr of obj = " << (void*)&obj << std::endl;
    std::cout << "offset of c = "  << offsetof(MyStruct,c) << std::endl;
    std::cout << "offset of i = " << offsetof(MyStruct,i) << std::endl;
    std::cout << "offset of s = " << offsetof(MyStruct,s) << std::endl;
    std::cout << "sizeof MyStruct = " << sizeof(MyStruct);
}

The execution results are as follows:

start addr of obj = 0x7ffe96c067a9
offset of c = 0
offset of i = 1
offset of s = 5
sizeof MyStruct = 7

First of all#pragma pack sets the alignment value to 1, the longest data type in the structure is int, and the length is also 4. Therefore the effective alignment value of the structure is 1.

For the c variable, there is no suspense, it will be ranked at the 0 offset address.

For variable i, the type is int, the length is 4, the minimum value of int and valid alignment value is, so i needs to be arranged on an integer multiple of 2, so the first offset that meets the requirements is 1.

For variable s, the type is short, the length is 2, the minimum value of short and the valid alignment value is 2, and the first address that meets the requirements is 5.

So far, the space size used is 7, which has met the requirement that the structure size be an integer multiple of the effective alignment value.

MyStruct distribution 3

Example 4:

#include <iostream>
#include <emmintrin.h>

struct MyStruct {
    
    
    char c;
    __m128i i;
};

int main()
{
    
    
    MyStruct obj;
    std::cout << "start addr of obj = " << (void*)&obj << std::endl;
    std::cout << "offset of c = "  << offsetof(MyStruct,c) << std::endl;
    std::cout << "offset of i = " << offsetof(MyStruct,i) << std::endl;
    std::cout << "sizeof MyStruct = " << sizeof(MyStruct);
}

The execution results are as follows:

start addr of obj = 0x7fff9d47cd90
offset of c = 0
offset of i = 16
sizeof MyStruct = 32

First, the longest data type in the structure is __m128i, with a length of 16. Therefore the effective alignment value of the structure is 16.

For the c variable, there is no suspense, it will be ranked at the 0 offset address.

For variable i, the type is __m128i, the length is 16, the minimum value of __m128i and the valid alignment value is 16, so i needs to be arranged on an integer multiple of 2, so the first offset that meets the requirements is 16.

MyStruct distribution 4

Example 5:

#include <iostream>
#include <emmintrin.h>

#pragma pack(8)
struct MyStruct {
    
    
    char c;
    __m128i i;
};

int main()
{
    
    
    MyStruct obj;
    std::cout << "start addr of obj = " << (void*)&obj << std::endl;
    std::cout << "offset of c = "  << offsetof(MyStruct,c) << std::endl;
    std::cout << "offset of i = " << offsetof(MyStruct,i) << std::endl;
    std::cout << "sizeof MyStruct = " << sizeof(MyStruct);
}

The execution results are as follows:

start addr of obj = 0x7ffddbec2c40
offset of c = 0
offset of i = 8
sizeof MyStruct = 24

First of all#pragma pack sets the alignment value to 8, and the longest data type in the structure is __m128i with a length of 16. Therefore the effective alignment value of the structure is 8.

For the c variable, there is no suspense, it will be ranked at the 0 offset address.

For variable i, the type is __m128i, the length is 16, the minimum value of __m128i and the valid alignment value is 8, so i needs to be arranged on an integer multiple of 2, so the first offset that meets the requirements is 8.

MyStruct distribution 5

Summarize

  • In order to access memory data efficiently, memory data usually needs to be aligned.
  • #pragma pack(n)Valid value for setting alignment. Setting an alignment value larger than the longest member of the structure will be invalid.

Guess you like

Origin blog.csdn.net/qq_31442743/article/details/132695982