The calculation method of structure size in C++

Foreword:
Speaking of C++, it is really a magical language. It is as obscure as your GirlFriend. You never know what her mood will be in the next second, but fortunately C++ is still a programming language after all After all, the tool is dead. Since it is dead, it is easy to handle. There is always a way to deal with it. When you click into this article, perhaps you are coming with doubts, or you have encountered the erratic size of the structure and you don’t know how to calculate it, or maybe you have not encountered such a problem, but it doesn’t matter what you call a rainy day. It's not a bad thing. Today, I will tell you about the calculation method of structure size in C++. Let’s not talk nonsense and go directly to today’s topic:

1. The number of bytes occupied by common types in C++

  • Those who are already veterans or familiar with the number of bytes occupied by C++ common types can skip this section.
  • The method of calculating the number of bytes occupied by a variable in C++ is the same as that of C, using the sizeof() function for calculation
  • Due to different operating systems and environments, the space occupied by the types displayed in your system will also be different from mine. This article has been subject to the blogger’s computer.
  • Can't remember? You can know the space occupied by executing it directly and rudely.
# include<iostream>
using namespace std;

int main(){
    
    
    cout << "char:\t\t" << sizeof(char) << endl;
    cout << "bool:\t\t" << sizeof(bool) << endl;
    cout << "short:\t\t" << sizeof(short) << endl;
    cout << "long:\t\t" << sizeof(long) << endl;
    cout << "int:\t\t" << sizeof(int) << endl; 
    cout << "float:\t\t" << sizeof(float) << endl;
    cout << "double:\t\t" << sizeof(double) << endl;
    cout << "long long:\t" << sizeof(long long) << endl;
}

Output result

type size (bytes)
char 1
bool 1
short 2
long 4
int 4
float 4
double 8
long long 8

2. The computer system of structure size in C++

  • Many people may think that the size of the structure is simply the addition of the size of its internal attributes, but in fact it is not the case. Look at the following example:
# include<iostream>
using namespace std;

struct TestStruct  
{
    
      
    char c;
    int i;     
};   


int main(){
    
    
    cout << sizeof(TestStruct);
}

After you execute it, you will find it strange that the output turned out to be 8. According to the previous guess, char occupies 1 byte + int occupies 4 bytes = 5 bytes, but the result is 8. But I'm very glad you read this article. Let's put this question aside first, and then come back to discuss this question after reading the computer system below;

  • First understand the concept of memory alignment
    (1) Why there is memory alignment: because in theory, any variable can be stored and retrieved from any address space, but in fact it is not the case, some specific types of variables It can only be accessed in a specific memory space, so these variables need to be arranged in the memory space according to certain rules, so they cannot be stored in the memory randomly. One is because some platforms only allow certain To access data at a specific memory address, the second is to increase the speed of variable access. For example, if I let the shaping exist on the memory address of the even-numbered address space, when I access it, I only need to traverse the even-numbered address space.
    (2) Alignment parameters: This is a very important point in memory alignment. Every different variable has its alignment parameters. Of course, the alignment parameters will be slightly different in different compilation environments, such as:
    Windows 32-bit/VC++ 6.0
    char bool short long int float double long long
    length 1 1 2 4 4 4 8 8
    Alignment parameter 1 1 2 4 4 4 8 8
    Linux 32nd / gcc
    char bool short long int float double long long
    length 1 1 2 4 4 4 8 8
    Alignment parameter 1 1 2 4 4 4 4 4
    It can be seen that under the 32-bit Linux system, the alignment parameters of the double and long long types have become 4. This is because under the 32-bit Linux/gcc environment, if the byte length of the variable type does not exceed the word length of the CPU , The length of the variable type will be used as the alignment length. If the word length of CUP is exceeded, the word length of CUP will be used as the alignment parameter of the variable. The word length of CUP under the 32-bit Linux system is 4, so double and The alignment parameters of the long long type are all 4. If you switch to a 64-bit operating system, it will become 8.
    (3) Two principles for alignment parameters in the structure :
    Principle 1 : The variables in the structure are relative to the structure The offset of the first address must be an integer multiple of the alignment parameter corresponding to the variable. At this time, the alignment parameter corresponding to the variable will be compared with the system default alignment parameter to choose the smaller of the two. For example, the alignment parameter in the int type table is 4. It must first be compared with the default alignment parameter 8 in the system, and the two smaller one is used as the alignment parameter of the int type variable, so here is 4. Then at this time The offset of the int type variable from the first address of the structure must be an integer multiple of 4 if it is not an integer multiple, it needs to be filled.
    Principle 2: The total space occupied by the structure must be an integer multiple of its alignment parameter. Note that the alignment parameter mentioned here is the alignment parameter of the structure. What is the alignment parameter of the structure? When calculating the alignment parameters of the structure, it will first compare the alignment parameters of all variables in the structure with the system default alignment parameters, and then take the smaller number between the two as the alignment parameters of the variables, and then the structure will be inside it. The alignment parameters of all the variables are selected to select the largest one, and then this number is compared with the system default alignment parameters, and the smaller one of the two is selected, and this number is used as the alignment parameter of the structure.

2. Understanding alignment parameters through examples

  • Let’s go back to the first example

    # include<iostream>
    using namespace std;
    
    struct TestStruct  
    {
          
            
        char c;
        int i;     
    };   
    
    
    int main(){
          
          
        cout << sizeof(TestStruct);
    }
    

    Output result: 8
    Why is this happening?
    Let’s analyze it: (1) First, we allocate space for variable c. Because c is of char type, it is the first variable to allocate memory space, so its current offset relative to the first address of the structure is still 0. After looking up the table, we can know that the alignment parameter corresponding to the char type is 1 and it is smaller than the default alignment parameter, so the alignment parameter is 1, and then because the offset is 0, it can be divisible by 1, then there is no need to fill directly to allocate One byte of space for variable c;
    (2) After allocating variable c, allocate space for variable i. Because i is of type int, its alignment parameter is 4 in the same way as above, but because 1 has been allocated before The byte space is given to c, so now the offset relative to the first address of the structure is 1, but 1 is not divisible by 4, so you need to fill in 3 empty bytes after the variable c to make the offset change Divide 4 to 4, and then allocate 4 bytes to variable i. Now the space occupied by the entire structure becomes 8 bytes
    (3) Finally, it is judged whether the space occupied by the structure meets the requirements, and the variable c The corresponding alignment parameter is 1, and the corresponding alignment parameter of the variable i is 4, then the larger one of them is 4, and then 4 is compared with the default alignment parameter 8, and the smaller one is the alignment corresponding to the structure The parameter is 4, and then divide the space occupied by the structure by 8 to find that it can be divided, so there is no need to fill it again. The final space occupied by the structure is 8 bytes;

  • Example 2:

    # include<iostream>
    using namespace std;
    
    struct TestStruct2  
    {
          
            
        char c;
        int i; 
        short s;    
    };   
    
    
    int main(){
          
          
        cout << sizeof(TestStruct2);
    }
    

    Output result: 12
    Explanation: Compared with the previous example, our example has an extra variable of type short in the structure. Then we will continue with the small point (2) above, because the c and i variables have already been assigned. So now the offset compared to the first address of the structure is 8, and we can easily know that the alignment parameter corresponding to short is 2. Now the offset is 8 and can be divisible by 2, so there is no need to fill in, and the variable s is directly assigned That's it, now the total size of the structure has become 10. Now let's calculate the corresponding alignment parameter of the structure, it is still 4, but now the total space occupied by the structure 10 cannot be divisible by 4, so it needs to be in the variable s 2 bytes are filled in the back, so the total space occupied by the structure now is 10 + 2 = 12 bytes.

  • Example 3:

    # include<iostream>
    using namespace std;
    
    struct TestStruct3  
    {
          
            
        char c;
        int i; 
        static short s;    
    };   
    
    
    int main(){
          
          
        cout << sizeof(TestStruct3);
    }
    

    Output result: 8
    Explanation: The only difference between this example and the previous example is that a static keyword is added in front of the short variable to modify, which will cause the variable s to run into the memory space of the global initialization area and store it in this area The variable of will not be retrieved by the sizeof keyword, so it is equivalent to that the variable in the structure is'invisible', it will not be calculated, then the result will return to the result of example 1;

  • Example 4:

    # include<iostream>
    using namespace std;
    
    struct TestStruct  
    {
          
            
        char c;
        int i;     
    };   
    
    struct TestStruct4  
    {
          
            
        int n;
        TestStruct t;   
    };
    
    int main(){
          
          
        cout << sizeof(TestStruct4);
    }
    

    Output result: 12
    Explanation: We found that in this example, a variable of another structure type is stored in the structure, so we need to clarify a concept first. The alignment parameters corresponding to the structure have already been mentioned above. Please pay attention It should not be confused with the space occupied by the structure. Here we can find the structure TestStruct and its corresponding alignment parameter is 4. We have already calculated it, here to analyze this example, in TestTruct4 we first allocate space for variable n, because it is the first one, and int corresponds to The alignment parameter is 4, so you can divide 0; then directly allocate 4 bytes to variable n, and now allocate space for variable t, because variable n has been allocated before, so the current offset compared to the first address is 4 , TestStruct type variable t corresponding to the alignment parameter is 4, 4 can be divided into 4 so it is directly allocated without filling, but the size of TestStruct is 8, so 8 spaces are allocated, so the space used by TestStruct4 now is 4 + 8 = 12 bytes. Finally, it is judged whether the second rule is satisfied, that is, the space occupied by the structure must be an integer multiple of its parameter corresponding to the structure. Obviously, the alignment parameter corresponding to TestStruct4 is 4, so that the occupied space 12 can be divisible by 4, then No need to fill, the real space occupied by the final structure TestStruct4 is 12.

4. Supplement: Set the default alignment parameters

  • After c++ 11, custom alignment parameters are supported. The specific methods are as follows

    # include<iostream>
    # pragma pack(8)
    
    struct TestStruct5  
    {
          
            
        int n;
        double d;
    };
    
    int main(){
          
          
        cout << sizeof(TestStruct5);
    }
    

    Output result: 16

    # include<iostream>
    # pragma pack(4)
    
    struct TestStruct5  
    {
          
            
        int n;
        double d;
    };
    
    int main(){
          
          
        cout << sizeof(TestStruct5);
    }
    

    Output result: 12

You can see that when you set different default values, the results are different. Readers can combine the previous inferences and think, so I won't talk about it here.

Written at the end:
After all, the program is dead, and people are flexible. Generally speaking, the problem is not a tool. The basic problem lies in the person. Everything that looks at metaphysics on the surface has rules inside. In other words, once you understand this law, it's not that magical to look back and forth. So when you start learning things, you can get a good idea, but if you want to go to the next level, you need to settle, chew slowly, come on!

Guess you like

Origin blog.csdn.net/qq_42359956/article/details/105877455