Article from Noalgo Blog original: C + + sizeof Memory calculation (2)
Memory control is a very important part of the program design process, the memory size used by sizeof to calculate data is a common means, but this problem involves a lot of basic programming details, can well reflect the basic skills of a programmer, become one of the common problems in written interview.
Here is a summary of some of the common problems, in view of the length of the problem, divided into two parts, here is the second part of the slightly advanced step.
- C + + sizeof memory calculation (1)
- C + + sizeof Memory calculation (2)
Three composite types
For basic data types, such as char, int, and double, the size of the memory in the computer is generally fixed, such as a 32-bit machine, with a size of 1Byte, 4Byte, and 8Byte. For a composite type, the amount of memory it occupies is very much related to the occurrence of the member variable, not always equal to the sum of the memory size of each data member.
To improve CPU access to memory, the compiler adjusts the location of the structure members in memory so that their addresses meet certain conditions, called memory alignment.
- The first address of a struct variable is an integer multiple of its longest base type member.
- The offset of each member in the struct relative to the first address of the struct is an integer multiple of the member size. Because the first address of a struct is an integer multiple of the longest type, the address of each member is also an integer multiple of its type length. If the length of a member is not sufficient to satisfy this condition, the compiler adds the appropriate padding bytes to the member to satisfy the requirement of integer times.
- The total size of a struct is an integer multiple of the size of the structure's widest base type member. If not, the compiler adds the appropriate padding bytes at the end of the struct.
- If the longest base type in the structure is longer than the number of bits in the processor, the units are aligned in multiples of the processor, otherwise, the longest base type inside the struct is aligned.
Refer to the output of the following code for details.
struct s1{int A;char b;}; struct S2{char A; int b;}; struct S3{char a;s1 s;}; struct S4{char a[13];int b;}; void Test () {printf ("int size:%d\n", sizeof (int)); int size: 4printf ("char Size:%d\n", sizeof (char)); Char Size: 1printf ("S1 Size:%d\n", sizeof (S1)); S1 Size: 8printf ("S2 Size:%d\n", sizeof (S2)); S2 Size: 8printf ("S3 Size:%d\n", sizeof (S3)); S3 Size: 12printf ("S4 Size:%d\n", sizeof (S4)); S3 Size: 20}
The length of the S1 member int is 4,char length of 1, and 4 is the structure-aligned unit. The offset of a is 0, which satisfies the condition. The offset of B is 4, which satisfies the condition. However, the overall length of 5 is not a multiple of 4, so the compilation is followed by 3 bytes, the overall length becomes 8.
While the offset of a in S2 is 0,b, the offset of 1,b does not satisfy the condition, so it fills 3 bytes between A and B to satisfy the condition.
The problem of structure nesting is involved in the S3, that is, there are other struct members in the struct members, and when looking for the widest basic type members, the struct members should be split to see that each member of the struct member is considered individually. So the S3 is 4 bytes to its unit of Int.
In S4, there are contiguous elements of the same type in the array, where each element is sequentially arranged in memory without padding bytes. However, the whole is still to satisfy the double-number of times the condition, if necessary, after padding bytes.
In-memory data alignment is a compile-time optimization operation, but we can specify memory-aligned alignment units when writing programs, such as using #pragma pack (n) to tell the compilation to align data in n-bytes, and restore the default alignment standard using #pragma pack ().
Note the amount of memory output in the following code differs from the result of the above code.
#pragma pack (1) struct s1{int A;char b;}; struct S2{char A; int b;}; struct S3{char a;s1 s;}; struct S4{char a[13];int b;}; void Test () {printf ("int size:%d\n", sizeof (int)); int size: 4printf ("char Size:%d\n", sizeof (char)); Char Size: 1printf ("S1 Size:%d\n", sizeof (S1)); S1 Size: 5printf ("S2 Size:%d\n", sizeof (S2)); S2 Size: 5printf ("S3 Size:%d\n", sizeof (S3)); S3 Size: 6printf ("S4 Size:%d\n", sizeof (S4)); S3 Size: 17}
Four inheritance
A data member in a class consumes a certain amount of memory, but the member function generally does not consume object memory. member functions are placed in the code area, and no space is allocated for the member function when the object is created, but all objects share this function code. Thus, for classes with empty classes or members that have only member functions, they occupy 1 bytes of memory.
However, when there is a virtual function in the member function, the situation will be different. The first thing to figure out is what is a virtual function, a virtual function in C + + in order to implement polymorphism and declared in the base class as virtual member function, the derived class can override this virtual function, you can use a pointer to the base class to implement the dynamic binding of the function call. When a virtual function is declared in a class, it implicitly contains a member variable: a virtual function pointer that points to a virtual function table, a virtual function table containing information about the class, and the addresses of all the virtual functions in the class. Therefore, the size of the empty class containing the virtual function needs to contain the size of the virtual pointer, that is, 4, and no matter how many virtual functions, the size is 4.
Class A{};class b{void F ();}; Class c{virtual void F ();}; Class d{virtual void f (); virtual void g ();}; void Test () {printf ("sizeof (a) =%d\n", sizeof (a)),//sizeof (a) =1printf ("sizeof (b) =%d\n", sizeof (b));//sizeof (b) = 1printf ("sizeof (c) =%d\n", sizeof (c)); sizeof (C) =4printf ("sizeof (d) =%d\n", sizeof (d)); sizeof (D) =4}
The following consider the changes in memory consumption when inheriting.
When inheriting, the subclass inherits the members of the parent class, although the private members of the parent class are not available in the subclass, but they also occupy the memory space of the child class. So the memory of the subclass is the sum of the memory occupied by the members of the subclass itself plus the inherited members of the parent class.
Class a{void F ();}; Class b{virtual void F ();}; Class Aa:public A{};class b1:public b{};class b2:public b{virtual void g ();}; void Test () {printf ("sizeof (a) =%d\n", sizeof (a)); sizeof (A) =1printf ("sizeof (b) =%d\n", sizeof (b)); sizeof (B) =4printf ("sizeof (AA) =%d\n", sizeof (AA)); sizeof (AA) =1printf ("sizeof (B1) =%d\n", sizeof (B1)); sizeof (B1) =4printf ("sizeof (B2) =%d\n", sizeof (B2)); sizeof (B2) =4}
C + + introduces the concept of virtual inheritance in order to achieve multiple inheritance. The main problem is that when both B and C inherit a, if D inherits B and C, then D will have two copies of the members of a, then the inheritance of B and C must be set to virtual inheritance.
Using virtual inheritance avoids copying multiple base class objects, unlike normal inheritance, which requires a pointer to a base class that occupies a size of 4. See the code below for the difference between Class D and Class E.
Class A{};class B:public virtual a{};class c:public virtual A{};class d:public B, public c{};class e:public Virtua L B, public virtual c{};void test () {printf ("sizeof (a) =%d\n", sizeof (a)),//sizeof (a) =1printf ("sizeof (B) =%d\n", sizeof ( B)); sizeof (B) =4printf ("sizeof (c) =%d\n", sizeof (c)); sizeof (C) =4printf ("sizeof (d) =%d\n", sizeof (d)); sizeof (D) =8printf ("sizeof (e) =%d\n", sizeof (e)); sizeof (E) =12}
With multiple inheritance of virtual inheritance, there are more than one virtual function table within a class, that is, multiple virtual pointers point to these tables.
Here is a more comprehensive example to summarize this part of the content.
Class A{char a;virtual void FA ();}; Class b:public a{virtual void FB ();}; Class C:public virtual a{virtual void FC ();}; Class D:public virtual a{virtual void FD ();}; Class E:public C, public d{virtual void FE ();}; Class F:public virtual C, public virtual d{virtual void FF ();}; void Test () {printf ("sizeof (a) =%d\n", sizeof (a)), printf ("sizeof (b) =%d\n", sizeof (b)), printf ("sizeof (C) =%d\n", sizeof (C)); printf ("sizeof (E) =%d\n", sizeof (d)); printf ("sizeof (e) =%d\n", sizeof (e)); printf ("sizeof (f) =%d\n", sizeof (f)); The program output is://sizeof (A) =8 virtual pointer & memory Alignment//sizeof (B) =8//sizeof (C) =16//sizeof (e) =16//sizeof (e) =24//sizeof (F) =32}
C + + sizeof Memory calculation (2)