memory allocation for structures elements

2019-02-24 07:14发布

问题:

Hi I am having difficulties in understanding about how the memory is allocated to the structure elements.

For example if i have the below structure and the size of char is 1 and int is 4 bytes respectively.

struct temp
{
char a;
int b;
};

I am aware that the size of the structure would be 8. Because there will be a padding of 3 bytes after the char, and the next element should be placed in multiple of 4 so the size will be 8.

Now consider the below structure.

struct temp
{
int a;     // size is 4
double b;  // size is 8
char c;    // size is 4
double d;  // size is 8
int e;     // size is 4
};

This is the o/p i got for the above strucure

size of node is 40
the address of node is 3392515152 ( =: base)
the address of a in node is 3392515152 (base + 0)
the address of b in node is 3392515160 (base + 8)
the address of c in node is 3392515168 (base + 16)
the address of d in node is 3392515176 (base + 24)
the address of e in node is 3392515184 (base + 32)

The total memory sum up to 36 bytes, why does it show as 40 bytes? If we create an array of such structure also the first element of the next array element can be place in 3392515188 (base + 36) as it is a multiple of 4, but why is it not happening this way?

Can any one plz solve my doubt.

Thanks in advance, Saravana

回答1:

It seems that on your system, double has to have the alignment of 8.

struct temp {
    int a;     // size is 4
    // padding 4 bytes
    double b;  // size is 8
    char c;    // size is 1
    // padding 7 bytes
    double d;  // size is 8
    int e;     // size is 4
    // padding 4 bytes
}; 
// Total 4+4+8+1+7+8+4+4 = 40 bytes

Compiler adds an extra 4 bytes to the end of struct to make sure that array[1].b will be properly aligned.

Without end padding (assuming array is at address 0):

&array[0]   == 0
&array[1]   == 36
&array[1].b == 36 + 8 == 44  
44 % 8 == 4  ->  ERROR, not aligned!

With end padding (assuming array is at address 0):

&array[0]   == 0
&array[1]   == 40
&array[1].b == 40 + 8 == 48
48 % 8 == 0  ->  OK!

Note that sizes, alignments, and paddings depend on target system and compiler in use.



回答2:

In your calculation, you ignore the fact that e is subject to be padded as well:

The struct looks like

0       8       16      24      32
AAAAaaaaBBBBBBBBCcccccccDDDDDDDDEEEEeeee

where uppercase is the variable itself, and lowercase is the padding applied to it.

As you see (and as well from the addresses), each field is padded to 8 bytes, which is the largest field in the structure.

As the structure might be used in an array, and all array elements should be well-aligned as well, the padding to e is necessary.



回答3:

It's heavily dependent on both your processor architecture and compiler. Modern machines and compilers may choose larger or smaller padding to reduce the access cost to data.

Four-byte alignment means that two address lines are unused. Eight, three. A chip can use that to address more memory (coarser grain) with the same amount of hardware.

A compiler might use a similar trick for various reasons, but no compiler is required to do anything but be no less fine-grained than the processor. Often, they'll just take the biggest-size value and use it exclusively for that block. In your case, that's a double, which is eight bytes.



回答4:

This is a compiler dependent behavior. Some compiler makes that 'double' to be stored after 8 bit offset.

IF you modify the structure as below you will get different result.

struct temp
{
double b;  // size is 8
int a;     // size is 4
int e;     // size is 4
double d;  // size is 8
char c;    // size is 4
}

Every programmer should know what padding you compiler is doing. E.g. If you are working on ARM platform and you set compiler settings to do not pad structure elements[ then accessing structure elements through pointers may generate 'odd' address for which processor generates an exception.



回答5:

Every structure will also have alignment requirements

for example :

typedef struct structc_tag { char c;`` double d; int s; } structc_t;

Applying same analysis, structc_t needs sizeof(char) + 7 byte padding + sizeof(double) + sizeof(int) = 1 + 7 + 8 + 4 = 20 bytes. However, the sizeof(structc_t) will be 24 bytes. It is because, along with structure members, structure type variables will also have natural alignment. Let us understand it by an example. Say, we declared an array of structc_t as shown below structc_t structc_array[3];

Assume, the base address of structc_array is 0×0000 for easy calculations. If the structc_t occupies 20 (0×14) bytes as we calculated, the second structc_t array element (indexed at 1) will be at 0×0000 + 0×0014 = 0×0014. It is the start address of index 1 element of array. The double member of this structc_t will be allocated on 0×0014 + 0×1 + 0×7 = 0x001C (decimal 28) which is not multiple of 8 and conflicting with the alignment requirements of double. As we mentioned on the top, the alignment requirement of double is 8 bytes. In order to avoid such misalignment, compiler will introduce alignment requirement to every structure. It will be as that of the largest member of the structure. In our case alignment of structa_t is 2, structb_t is 4 and structc_t is 8. If we need nested structures, the size of largest inner structure will be the alignment of immediate larger structure.

In structc_t of the above program, there will be padding of 4 bytes after int member to make the structure size multiple of its alignment. Thus the sizeof (structc_t) is 24 bytes. It guarantees correct alignment even in arrays. You can cross check



回答6:

to avoid structure padding! #pragma pack ( 1 ) directive can be used for arranging memory for structure members very next to the end of other structure members.

#pragma pack(1)
struct temp
{
int a;     // size is 4
int b;     // size is 4
double s;  // size is 8
char ch;   //size is 1
};

size of structure would be:17



回答7:

If we create an array of such structure also the first element of the next array element can be place in 3392515188 (base + 36) as it is a multiple of 4, but why is it not happening this way?

It can't because of the double elements in there.

It's clear that the compiler and architecture you are using requires a double to be eight byte aligned. This is obvious because there is seven bytes of padding after the char c.

This requirement also means that the entire struct must be eight byte aligned. There's no point in carefully making all the doubles aligned to eight bytes relative to the start of the struct if the struct itself is only four byte aligned. Hence the padding after the final int to make sizeof(temp) a multiple of eight.

Note that this alignment requirement need not be a hard requirement. The compiler could choose to do the alignment even if doubles can be four byte aligned on the grounds that it might take more memory cycles to access the double if it's only four byte aligned.