[C/C++] Memory alignment (super detailed, just read this article)

Table of contents

1. Why do we need memory alignment

2. The size of the basic variable type

3. The situation that affects memory alignment

Fourth, the conclusion first (important)

5. Give hundreds of millions of examples (the following content has been actually run, quality assurance)

 Example 1: Study the memory alignment problem of the last member of the structure 1

 Example 2: Study the memory alignment problem of the last member of the structure 2

 Example 3: Investigating the memory alignment of arrays

Example 4: Memory alignment between enumeration & study arrays

Example 5: Structure Nesting 1

Example 6: Structure Nesting 2

Example 7: __attribute__((packed)) 

Example 8:#pragma pack(n)

        Written in front: The environment used in this experiment: Windows 10 Visual Studio (64-bit), Ubuntu 18.04 x86_64-linux-gnu (64-bit)! !

1. Why do we need memory alignment

        Simply put, it is convenient for the computer to read and write data.

        Aligned addresses are generally multiples of n (n = 2, 4, 8).

        (1). A variable of 1 byte, such as a variable of char type, is placed at any address;

        (2). 2-byte variables, such as short- type variables, are placed at addresses that are integer multiples of 2 ;

        (3). Variables of 4 bytes, such as variables of float and int types, are placed at addresses that are integer multiples of 4 ;

        (4). 8-byte variables, such as long long and double type variables, are placed on addresses that are integer multiples of 8 ;

2. The size of the basic variable type

        Note: Pay special attention to the parts marked in blue! !

type of data ILP32 (32-bit Linux system) LP64 (most 64-bit Linux systems) LLP64 (64-bit Windows system)
char 1 byte 1 byte 1 byte
short 2 bytes 2 bytes 2 bytes
int 4 bytes 4 bytes 4 bytes
float 4 bytes 4 bytes 4 bytes
long 4 bytes 8 bytes 4 bytes
double 8 bytes 8 bytes 8 bytes
long long 8 bytes 8 bytes 8 bytes
pointer point 4 bytes 8 bytes 8 bytes
Enumeration enum 4 bytes 4 bytes 4 bytes
union Take the largest variable type size in the union Take the largest variable type size in the union Take the largest variable type size in the union

ILP32 refers to int, long and point are 32 bits.

LP64 means long and point are 64 bits.

LLP64 means long long and point are 64 bits.

3. The situation that affects memory alignment

1. Variable order.

2. __attribute__((packed)) : Cancel variable alignment , and align according to the actual number of bytes occupied (that is, make the variables arranged tightly without leaving gaps). (Only supported by gcc) See Example 7 for details.

3. #pragma pack (n) : Forces the variable to be aligned according to a multiple of n , and will affect the completion of the end address of the structure (see the description of the end address completion in general in 4 for details). See Example 8 for details.

Fourth, the conclusion first (important)

The following conclusions are made under the system default alignment rules:

Usually , the rules I summarized are as follows: In the middle of the structure : the starting address of each structure is placed according to the default rules of each type of variable , but except for char type variables (see 1 for details), char type variables generally follow the address in multiples of 2 Start saving. See Example 2 for details. The last of the structure (important) : depending on which one is the largest type in the structure , if it is 4 bytes like the int type, and the end address of the structure does not satisfy a multiple of 4, it will go to the nearest multiple of 4 Address completion; if it is 8 bytes like the double type, and the end address of the structure does not meet the multiple of 8, it will be completed to the nearest multiple of 8 address; and so on. . . .

Structure nesting : The starting address of the member variable of the substructure depends on the largest variable type in the substructure . For example, struct a contains struct b, and b contains elements such as char, int, double, etc., then b should be an integer from 8 times to start storing. See Example 5 and Example 6 for details.

Including array members : such as char a[5], its alignment is the same as writing five char type variables continuously, that is to say, it is still aligned by one byte . See Example 1, Example 2, Example 3, Example 4, and Example 5 for details.

Contains union members : take the integer multiple address of the largest type in the union and start storing. See Example 5 for details.

Personal summary ability is limited, it is easier to understand by watching examples:

5. Give hundreds of millions of examples (the following content has been actually run, quality assurance)

64-bit unless otherwise specified! !

 Example 1: Study the memory alignment problem of the last member of the structure 1

struct stu1 {
    char a[18];
    double b;
    char c;
    int d;
    short e;
};

 Windows 10: 48 bytes Ubuntu 18.04: 48 bytes

 Example 2: Study the memory alignment problem of the last member of the structure 2

struct stu1 {
    char a[18];
    int b[3];
    short c;
    char d;
    int e;
    short f;
};

 Windows 10: 44 bytes Ubuntu 18.04: 44 bytes

 Example 3: Investigating the memory alignment of arrays

struct stu1 {
    int a;
    char b[8];
    float c;
    short d;
};

 Windows 10: 20 bytes Ubuntu 18.04: 20 bytes 

Example 4: Memory alignment between enumeration & study arrays

enum DAY {
    MON = 1, TUE, WED, THU, FRI, SAT, SUN
};
struct stu1 {
    char a[5];
    char b[3];
    enum DAY day;
    int *c;
    short d;
    int e;
};

  Windows 10: 32 bytes        Windows 10 (32-bit): 24 bytes         Ubuntu 18.04: 32 bytes 

64 bit:

32 bit: 

Example 5: Structure Nesting 1

struct stu2 {
    char x;
    int y;
    double z;
    char v[6];
};
struct stu1 {
    union u1 {
        int a1;
        char a2[5];
    }a;
    struct stu2 b;
    int c;
};

  Windows 10: 40 bytes Ubuntu 18.04: 40 bytes

Example 6: Structure Nesting 2

struct stu2 {
    char x;
    int y;
    double z;
    char v[6];
};
struct stu1 {
    char a;
    struct stu2 b;
    int c;
};

   Windows 10: 40 bytes Ubuntu 18.04: 40 bytes

Example 7: __attribute__((packed)) 

Since both VS and VScode do not support __attribute__((packed)), only use gcc to compile.

struct __attribute__((packed)) stu1 {    // 取消内存对齐
    char a;
    long b;
    short c;
    float d;
    int e;
};

Ubuntu 18.04: 19 bytes

Example 8: #pragma pack(n)

#pragma pack (2)    // 强制以 2 的倍数进行对齐
struct stu1 {
    short a;
    int b;
    long c;
    char d;
};
#pragma pack ()    // 取消强制对齐,恢复系统默认对齐

   Windows 10: 12 bytes Ubuntu 18.04: 16 bytes

normal circumstances: 

Windows 10:

 Ubuntu 18.04:

Guess you like

Origin blog.csdn.net/weixin_48896613/article/details/127371045