Structure padding что это

от admin

Struct Padding in C: Overview, Examples, Visuals

A struct in C is a composite data type that allows you to group multiple variables together and store them in the same block of memory. If you’re familiar with Java, they’re a little similar to class definitions. In the picture above, a struct is being used to represent a “student” type, that has a name, age, gpa, and is_cs_major boolean value associated with if they are a cs major. Also note that the…

# Structure Padding and Packing

By default, C compilers lay out structures so that each member can be accessed fast, without incurring penalties for ‘unaligned access, a problem with RISC machines such as the DEC Alpha, and some ARM CPUs.

Depending on the CPU architecture and the compiler, a structure may occupy more space in memory than the sum of the sizes of its component members. The compiler can add padding between members or at the end of the structure, but not at the beginning.

Packing overrides the default padding.

# Packing structures

By default structures are padded in C. If you want to avoid this behaviour, you have to explicitly request it. Under GCC it’s __attribute__((__packed__)) . Consider this example on a 64-bit machine:

The structure will be automatically padded to have 8-byte alignment and will look like this:

So sizeof(struct foo) will give us 24 instead of 17 . This happened because of a 64 bit compiler read/write from/to Memory in 8 bytes of word in each step and obvious when try to write char c; a one byte in memory a complete 8 bytes (i.e. word) fetched and consumes only first byte of it and its seven successive of bytes remains empty and not accessible for any read and write operation for structure padding.

# Structure packing

But if you add the attribute packed , the compiler will not add padding:

Now sizeof(struct foo) will return 17 .

Generally packed structures are used:

  • To save space.
  • To format a data structure to transmit over network without depending on each architecture alignment of each node of the network.

It must be taken in consideration that some processors such as the ARM Cortex-M0 do not allow unaligned memory access; in such cases, structure packing can lead to undefined behaviour and can crash the CPU.

# Structure padding

Suppose this struct is defined and compiled with a 32 bit compiler:

We might expect this struct to occupy only 10 bytes of memory, but by printing sizeof(str_32) we see it uses 12 bytes.

This happened because the compiler aligns variables for fast access. A common pattern is that when the base type occupies N bytes (where N is a power of 2 such as 1, 2, 4, 8, 16 — and seldom any bigger), the variable should be aligned on an N-byte boundary (a multiple of N bytes).

For the structure shown with sizeof(int) == 4 and sizeof(short) == 2 , a common layout is:

  • int a; stored at offset 0; size 4.
  • short b; stored at offset 4; size 2.
  • unnamed padding at offset 6; size 2.
  • int c; stored at offset 8; size 4.

Thus struct test_32 occupies 12 bytes of memory. In this example, there is no trailing padding.

The compiler will ensure that any struct test_32 variables are stored starting on a 4-byte boundary, so that the members within the structure will be properly aligned for fast access. Memory allocation functions such as malloc() , calloc() and realloc() are required to ensure that the pointer returned is sufficiently well aligned for use with any data type, so dynamically allocated structures will be properly aligned too.

Structure padding in C- Data Structures

In this article we will learn about the structure padding in C in detail.

Table of contents:

Let’s recall some basics

The memory is assigned/allocated to the members of structure only after the object is declared. Once we declare the object continuous block of memory is allocated to the structure memory.
It will be allocated sequence wise as they are declared.

Exit fullscreen mode

Why structure padding?

Let’s understand with an example:

Exit fullscreen mode

Normally what we do to calculate the size of the structure is add the size of all the data members present in the structure.
So considering the above given size of every data type ,the size of structure object is 6 bytes acc to our general rule.

But this answer is wrong. Now, we will understand why this answer is wrong? We need to understand the concept of structure padding.

Concept of padding

  • The processor reads 1 word at a time not 1 byte at a time.
  • A 32-bit processor -> 1 word at a time-> 4 bytes-> 1 CPU cycle (1 word=4 bytes).
  • A 64-bit processor -> 1 word at a time-> 8 bytes-> 1 CPU cycle (1 word=8 bytes).
  • The number of CPU cycles are inversely proportional to performance .
  • It means the more number of cycles CPU takes for performing a specific task the lesser will be it’s performance.
  • With increase in the number of CPU cycles the performance is decreasing.

text box-0

  • This is evident that it is an unnecessary wastage of CPU cycles. And here the concept of structure padding is introduced.

How it works?

It is done by the compiler automatically and it saves the no of CPU cycles and hence improves the performance.
allocation 2
text box-1

Now the size of the object is 8 bytes not 6 bytes.
For more clarification let’s discuss the distribution of space:

  • A occupied=1 byte.//char datatype
  • B occupied=1 byte//char datatype
  • Vacant rows created occupied=2 bytes C occupied= 4 bytes.//int datatype.

Hence the size of the structure object is 1+1+2+4=8 bytes.
So here we have improved the performance but the memory is wasted due to creation of vacant rows.

More examples to understand better

Let’s look at another example :

Exit fullscreen mode

Let’s look at the allocation of memory:
allocation 3

The total size of the structure object is 4+4+4=12 bytes.

Читать:
Игра june s journey чем заканчивается

How to avoid the structure padding in C?

The structural padding is an in-built process that is automatically done by the compiler. Sometimes we need to avoid it because it increases the size of the structure from it’s actual size.

We can avoid padding using 2 ways:

  • Rearranging the attribute.
  • Using #pragma pack(1)

Rearrangement of attributes/variables.
There is one way to reduce the memory wastage manually due to padding.
We can align the data variables in such order that the variable containing more size will be declared first and then the variables having small size should be declared.

Understand through example.

Exit fullscreen mode

Let’s look at the allocation:
allocation 4

The total size of the struct object is 4+1+1=6 bytes.

Using #pragma pack(1) directive

Exit fullscreen mode

allocation 5
Here if we avoid using pragma here then the size of the object structure will be 4+4+4+4=16 bytes.
But the actual size of the structure members is 13 bytes, so 3 bytes are wasted. To avoid the wastage of memory, we use the #pragma pack(1) directive to provide the 1-byte packaging.

Structure padding and packing

The sizes of the structures are 12 and 8 respectively.

Are these structures padded or packed?

When does padding or packing take place?

gsamaras's user avatar

11 Answers 11

Padding aligns structure members to «natural» address boundaries — say, int members would have offsets, which are mod(4) == 0 on 32-bit platform. Padding is on by default. It inserts the following «gaps» into your first structure:

Packing, on the other hand prevents compiler from doing padding — this has to be explicitly requested — under GCC it’s __attribute__((__packed__)) , so the following:

would produce structure of size 6 on a 32-bit architecture.

A note though — unaligned memory access is slower on architectures that allow it (like x86 and amd64), and is explicitly prohibited on strict alignment architectures like SPARC.

(The above answers explained the reason quite clearly, but seems not totally clear about the size of padding, so, I will add an answer according to what I learned from The Lost Art of Structure Packing, it has evolved to not limit to C , but also applicable to Go , Rust .)

Memory align (for struct)

Rules:

  • Before each individual member, there will be padding so that to make it start at an address that is divisible by its alignment requirement.
    E.g., on many systems, an int should start at an address divisible by 4 and a short by 2.
  • char and char[] are special, could be any memory address, so they don’t need padding before them.
  • For struct , other than the alignment need for each individual member, the size of whole struct itself will be aligned to a size divisible by strictest alignment requirement of any of its members, by padding at end.
    E.g., on many systems, if struct’s largest member is int then by divisible by 4, if short then by 2.

Order of member:

  • The order of member might affect actual size of struct, so take that in mind. E.g., the stu_c and stu_d from example below have the same members, but in different order, and result in different size for the 2 structs.

Address in memory (for struct)

Empty space:

  • Empty space between 2 structs could be used by non-struct variables that could fit in.
    e.g in test_struct_address() below, the variable x resides between adjacent struct g and h .
    No matter whether x is declared, h ‘s address won’t change, x just reused the empty space that g wasted.
    Similar case for y .

Example

(for 64 bit system)

memory_align.c:

Execution result — test_struct_padding() :

Execution result — test_struct_address() :

Thus address start for each variable is g:d0 x:dc h:e0 y:e8

enter image description here

Eric's user avatar

I know this question is old and most answers here explains padding really well, but while trying to understand it myself I figured having a «visual» image of what is happening helped.

The processor reads the memory in «chunks» of a definite size (word). Say the processor word is 8 bytes long. It will look at the memory as a big row of 8 bytes building blocks. Every time it needs to get some information from the memory, it will reach one of those blocks and get it.

Variables Alignment

As seem in the image above, doesn’t matter where a Char (1 byte long) is, since it will be inside one of those blocks, requiring the CPU to process only 1 word.

When we deal with data larger than one byte, like a 4 byte int or a 8 byte double, the way they are aligned in the memory makes a difference on how many words will have to be processed by the CPU. If 4-byte chunks are aligned in a way they always fit the inside of a block (memory address being a multiple of 4) only one word will have to be processed. Otherwise a chunk of 4-bytes could have part of itself on one block and part on another, requiring the processor to process 2 words to read this data.

The same applies to a 8-byte double, except now it must be in a memory address multiple of 8 to guarantee it will always be inside a block.

This considers a 8-byte word processor, but the concept applies to other sizes of words.

The padding works by filling the gaps between those data to make sure they are aligned with those blocks, thus improving the performance while reading the memory.

However, as stated on others answers, sometimes the space matters more then performance itself. Maybe you are processing lots of data on a computer that doesn’t have much RAM (swap space could be used but it is MUCH slower). You could arrange the variables in the program until the least padding is done (as it was greatly exemplified in some other answers) but if that’s not enough you could explicitly disable padding, which is what packing is.

Похожие статьи