C Language Memory Alignment instance detailed _c language

Source: Internet
Author: User

This paper describes in detail the concept and usage of memory in C language programming. Share for everyone to use for reference. Specifically as follows:

First, byte alignment basic concept

The memory space in modern computers is divided by byte, theoretically, it seems that access to any type of variable can begin at any address, but the reality is that access to a particular type of variable is often at a specific memory address, which requires that various types of data be arranged in space according to certain rules, Instead of sequencing one after another, that's the alignment. The function and reason of the alignment: each hardware platform has a great difference in the processing of storage space. Some platforms have access to certain types of data only from certain addresses. For example, some of the architecture of the CPU to access a variable does not have to be aligned, when the error occurs, then programming in this architecture must ensure byte alignment. Other platforms may not, but the most common is the loss of access efficiency if the data is not aligned according to its platform requirements. For example, some platforms start every time from the even address, if an int (assuming 32-bit system) if stored in the beginning of the even address, then a read cycle can read out the 32bit, and if the location of the beginning of the odd address, it will take 2 reading cycles, The 32bit data can be obtained by piecing together the high and low byte of the results of two readings. Obviously, the reading efficiency is much lower.

See the following structure:

struct Struct1 
{ 
  double dda; 
  Char CDA; 
  int ida; 
}; 
sizeof (STRUCT1) =?

The wrong method of seeking:

sizeof (STRUCT1) =sizeof (double) +sizeof (char) +sizeof (int) =13

But when you run the following test code:

#include <stdio.h>
struct mystruct
{
  double dda;
  Char CDA;
  int ida;
};
int main ()
{
  struct mystruct ss;
  printf ("%d\n", sizeof (SS));
  return 0;
}

The results of the operation are: 16

In fact, this is a compiler's special handling of variable storage. To increase the CPU's storage speed, the compiler "aligns" the starting addresses of some variables. By default, the compiler states that each member variable must hold an offset from the starting address of the struct at a multiple of the number of bytes occupied by the type of the variable. The common types of alignment are listed below:

Type alignment (the offset at which the variable holds the starting address relative to the structure's starting address)

Char offset must be a multiple of sizeof (char) or 1

The int offset must be a multiple of sizeof (int), or 4

Float offset must be a multiple of sizeof (float) or 4

Double offset must be sizeof (double) that is a multiple of 8

The short offset must be a sizeof (short) that is a multiple of 2

Each member variable applies space in the order in which it appears in the structure, and adjusts the position according to the alignment above, and the empty byte compiler is automatically populated. At the same time, the compiler ensures that the size of the structure is a multiple of the number of bytes in the structure (that is, the number of bytes in the structure that occupies the maximum space), so when the space is requested for the last member variable, the empty bytes are automatically populated as needed

Now let's analyze how the compiler holds the structure:

struct Struct1 
{ 
  double dda; 
  Char CDA; 
  int ida; 
}; 

The first member DDA allocates space with the starting address the same as the starting address of the structure (offset 0 is just a multiple of sizeof), which occupies sizeof (double) = 8 bytes; Next, the second member CDA allocates space, The next address that can be allocated is 8 offset from the start address of the structure. is a multiple of sizeof (char), the CDA is stored in an offset of 8, which occupies the sizeof (char) = 1 bytes; Next, the third member Ida allocates space , at which point the next available address is 9 offset from the starting address of the struct, not a multiple of the sizeof (int) =4, and in order to satisfy the alignment constraint on the offset, VC automatically fills 3 bytes (these three bytes do not put anything), At this point, the next address that can be allocated is 12 of the offset of the structure's starting address, just a multiple of the sizeof (int) =4, so the IDA is stored in the offset of 12, which occupies sizeof (int) = 4 bytes At this time, the member variables of the entire structure have been allocated space, the total space size is: 8+1+3+4=16, just for the structure of the number of bytes (that is, the type of maximum space in the structure occupied by the number of bytes sizeof (double) =8) multiples, no vacant bytes need to be populated. So the size of the entire structure is: sizeof (STRUCT1) =8+1+ 3+4=16, of which 3 bytes are automatically filled with VC, without any meaningful things.

Let's take another example and swap the position of the STRUCT1 member variable above to make it the following:

struct Mystruct2
{
  char cda;
  Double dda;
  int ida;
};

The results of the operation are: 24

struct Mystruct2
{
  char cda;  The offset is 0, the alignment is the same, the CDA occupies 1 bytes;
  double dda;//The next available address has an offset of 1, not a multiple of sizeof (double) =8 
         //, which requires 7 bytes to be offset to 8 (satisfied alignment 
         //mode), so VC automatically fills in 7 bytes, DDA is placed on an offset 
         of 8//, it occupies 8 bytes. 

  int Ida;   The next available address has an offset of 16, is the sizeof (int) =4 times 
         //number, satisfies the int alignment, therefore does not need the VC automatic filling, the type saves 
         //puts on the address which the offset is 16, it occupies 4 bytes.
  
  //All member variables are allocated space, the total size of the space is 1+7+8+4=20, not struct 
  //The number of nodes (that is, the type of maximum space in the structure occupied by the number of bytes sizeof 
  //(double) =8) multiples, Therefore, you need to populate 4 bytes to meet the size of the structure as a multiple of the 
  //sizeof (double) =8.
};

So the total size of the structure is: sizeof (STRUCT2) is 1+7+8+4+4=24. One of the total 7+4=11 byte is automatically filled with VC, did not put any meaningful things.

Second, #pragma pack (n) to set the variable in n-byte alignment

The special handling of the storage of the structure of VC does increase the speed of the CPU storage variable, but sometimes it also brings some trouble, we also shield off the default alignment of the variable, we can set the alignment of the variable. VC provides the #pragma pack (n) to set the variable in n-byte alignment. N-byte alignment means that the offset of the starting address of the variable is stored in two ways:

First, if n is greater than or equal to the number of bytes occupied by the variable, the offset must satisfy the default alignment;

Second, if n is less than the number of bytes occupied by the type of the variable, the offset is a multiple of n, and the default alignment is not met.

The total size of the structure also has a constraint, in the following two cases: if n is greater than the number of bytes occupied by all member variable types, the total size of the structure must be a multiple of the space occupied by the most space-consuming variable, otherwise it must be a multiple of n. The following examples illustrate its use:

#pragma pack (push)//Save alignment Status 
#pragma pack (4)//set to 4 byte alignment 
struct test 
{ 
char M1; 
Double M4; 
int m3; 
}; 
#pragma pack (POP)//restore alignment status 

The size of the above structure is 16, the following analysis of its storage, first for the M1 allocation of space, its offset is 0, to meet our own set alignment (4-byte alignment), M1 occupies 1 bytes. It then starts allocating space for the M4, with an offset of 1, which needs to complement 3 bytes, so that the offset is a multiple of n=4 (because sizeof (double) is greater than N), and M4 occupies 8 bytes. The space is then allocated for the M3, with an offset of 12, a multiple of 4, and a M3 of 4 bytes. Space has been allocated for all member variables, 4+8+4=16 bytes are allocated, and a multiple of n is satisfied. If the above #pragma pack (4) is changed to #pragma pack (16), then we can get the size of the structure to be 24.

Let's look at the following example:

#pragma pack (8)
struct s1{
  char A;
  Long b;
};
struct S2 {
  char C;
  struct S1 D;
  Long long e;
};
#pragma pack ()

There is an important condition for member alignment, that is, each member is aligned separately. That is, each member is aligned in its own way.

This means that although the above specifies a 8-byte alignment, not all members are aligned in 8 bytes. Its alignment is the rule that each member is aligned with its type (usually the size of this type) and the specified alignment parameter (here is 8 bytes) The smaller of the alignment. And the length of the structure must be an integer multiple of all the alignment parameters used, not enough to fill the byte.

In S1, member A is 1 bytes by default by 1-byte alignment, specifies that the alignment parameter is 8, the values are 1,a by 1 bytes, member B is 4 bytes, the default is 4-byte alignment, then the 4 byte is aligned, so sizeof (S1) should be 8;

In S2, like a in C and S1, 1-byte alignment, and D is a struct, which is 8 bytes, and what does it align? For a struct, its default alignment is the largest of the alignment parameters used by all its members, and the S1 is 4. Therefore, member D is aligned by 4 bytes. Member E is 8 bytes , which is aligned by default by 8 bytes, as specified, so it's on the 8-byte boundary, at this point, 12 bytes have been used, so added 4 bytes of space, starting with the 16th byte of member E. At this point, the length is 24, which can already be divisible by 8 (Member E is aligned by 8 bytes). In this way, sizeof (S2) is 24 bytes.

Here are three important points:

1. Each member is aligned in its own way and can minimize length.

2. The default alignment of a complex type, such as a struct, is the alignment of its longest member, so that the length can be minimized when the member is a complex type.

3. The length of the alignment must be an integer multiple of the largest alignment parameter in the member, so that each entry is guaranteed to be aligned when the array is processed.

Three, Minix in the Stdarg.h file alignment

In the Minix stdarg.h file, the following macro is defined:

/* Amount of required in a argument list for type type.
 * Type may alternatively be a expression whose type is used.
 *

/#define __VA_ROUNDED_SIZE (type) \ ((
 sizeof (type) + sizeof (int)-1)/sizeof (int)) * sizeof (int))

The role of memory alignment can be seen from comments and the name of the macro. Based on the previous theory of C language memory alignment

N-byte alignment means that the offset of the starting address of the variable is stored in two ways:

First, if n is greater than or equal to the number of bytes occupied by the variable, the offset must meet the default alignment (the offset of the starting address of each member variable must be a multiple of the number of bytes occupied by the type of the variable) in relation to the starting address of the struct;

Second, if n is less than the number of bytes occupied by the type of the variable, the offset is a multiple of n, and the default alignment is not met.

At this point n = 4, for sizeof (TYPE) must be a natural number, sizeof (int)-1 = 3

sizeof (TYPE) can only occur in the following two cases:

(1) When sizeof (type) >= 4, offset = (sizeof (type)/4) *4

(2) when sizeof (TYPE) < 4, offset = 4

At this time sizeof (type) = 1 or 2 or 3, while (sizeof (type) + 3)/4 = 1

In order to unify the above two conditions, the offset = ((sizeof (TYPE) + 3)/4) * 4

In some source code, the memory to the Zihong __va_rounded_size through the bitwise operation to implement, the code is as follows:

#define __VA_ROUNDED_SIZE (type) \
  ((sizeof (type) +sizeof (int)-1) &~ (sizeof (int)-1))

Because of ~ (sizeof (int) –1) = ~ (4-1) =~ (00000011B) =11111100b

(sizeof (TYPE) + sizeof (int) –1 increases the number greater than 4m but less than or equal to 4 (m+1) to greater than or equal to 4 (m+1) but less than 4 (m+2), so & ~ (sizeof (int) –1) Then the original length was filled to a multiple of 4.

I believe that this article on the C program design of the learning of a certain reference value.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.