Struct Padding in C++

Structure padding and packing

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:

struct mystruct_A {
char a;
char gap_0[3]; /* inserted by compiler: for alignment of b */
int b;
char c;
char gap_1[3]; /* -"-: for alignment of the whole struct in an array */
} x;

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:

struct __attribute__((__packed__)) mystruct_A {
char a;
int b;
char c;
};

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.

Structures padding in C

It all comes down to alignment. The compiler wants to keep each element aligned to an address that's a multiple of that item's size, because the hardware can access it most efficiently that way. (And on some architectures, the hardware can only access it that way); unaligned access are disallowed.)

You've got one element in your structure that's a long int of size 8, so its alignment is going to drive everything else. Here's how your first structure would be laid out:

   0   1   2   3   4   5   6   7
+---+---+---+---+---+---+---+---+
0 | a | b | pad | c |
+---+---+---+---+---+---+---+---+
8 | d |
+---+---+---+---+---+---+---+---+
16 | e | padding |
+---+---+---+---+---+---+---+---+

So, as you can see, the size is 24, including two invisible, unnamed "padding" fields of 2 and 4 bytes, respectively.

Structure padding and alignment can be confusing. (It took me an embarrassingly large number of tries to get this answer right.) Fortunately, you usually don't have to worry about any of this, because it's the compiler's problem, not yours.

You can get the compiler to tell you how it's laying a structure out by using the offsetof macro:

int main(void){
printf("a @ %zd\n", offsetof(struct test, a));
printf("b @ %zd\n", offsetof(struct test, b));
printf("c @ %zd\n", offsetof(struct test, c));
printf("d @ %zd\n", offsetof(struct test, d));
printf("e @ %zd\n", offsetof(struct test, e));
printf("size = %zd\n", sizeof(struct test));
return 0;
}

On my machine (which seems to be behaving the same as yours) this prints:

a @ 0
b @ 1
c @ 4
d @ 8
e @ 16
size = 24

Notice that I have used %zd instead of %d, since sizeof and offsetof give their answers as type size_t, not int.

When you added char fields f, g, h, and i, they could fit into the second padding space, without making the overall structure any bigger. It was only when you added j that it pushed things over into another 8-byte chunk:

   0   1   2   3   4   5   6   7
+---+---+---+---+---+---+---+---+
0 | a | b | pad | c |
+---+---+---+---+---+---+---+---+
8 | d |
+---+---+---+---+---+---+---+---+
16 | e | f | g | h | i |
+---+---+---+---+---+---+---+---+
24 | j | padding |
+---+---+---+---+---+---+---+---+

Padding in a struct

The second question is implementation-defined (and in reality, so is the first, but I'll show you why you're getting the spacing you're getting regardless). Your platform is apparently 64-bit, and as such your data pointers are likewise (64-bit). With that, we peek at the structures.


stru_12

typedef struct 
{
int i;
char *str;
} stru_12;

This is aligned so str always falls on a 8-byte boundary, including in a contiguous sequence (an array). To do that, 4 bytes of padding are introduced between i and str.

0x0000 i    - length=4
0x0004 pad - length=4
0x0008 ptr - length=8
======================
Total 16

An array of these will always have ptr on an 8-byte boundary provided the array starts on said-same (which it will). Because the addition of padding between i and str also brought the structure size to a multiple of 8, no additional padding is required beyond this.


stru_13

Now, consider how that is also achieved with this:

typedef struct 
{
int i;
char *str;
char c;
} stru_13;

The same padding will apply between i and str to once-again place str on an 8-byte boundary, but the addition of c complicates things. To accomplish the goal of pointers always residing on 8-byte boundaries (including a sequence/array of these structures) the structure needs tail padding, but how much? Well, I hope it is obvious the overall structure size needs to be a multiple of 8 to ensure any embedded pointers (which are also on multiples of 8) are properly aligned. In this case, seven bytes of tail-padding are added to bring the size to 24 bytes:

0x0000 i    - length=4
0x0004 pad - length=4
0x0008 ptr - length=8
0x0010 c - length=1
0x0011 pad - length=7
======================
Total 24

stru_13 (part deux)

So try this. What might you think the same fields we had before, but ordered differenty, will result with:

typedef struct 
{
char *str;
int i;
char c;
} stru_13;

Well, we know we want str on an 8-byte boundary and i on a 4-byte boundary, and frankly couldn't care less about c (always a brides-maid):

0x0000 ptr  - length=8
0x0008 i - length=4
0x000c c - length=1
0x000d pad - length=3
======================
Total 16

Run that though your test program and you'll see it pans out as we have above. It reduces to 16-bytes. All we did was change the order to a space-friendlier layout that still supported our requirements, and we reduced the default representation by 8 bytes (one third of the original structure with the prior layout). To say that is an important thing to take away from all this would be an understatement.

Assumption of structure padding in C

However, this does build on the assumption that the first member of struct will be stored immediately after word boundary. Is it always so?

Yes.

When a structure type is defined, the alignment requirement of the structure will be at least the strictest alignment requirement of its members. For example, if a structure has members with alignment requires of 1 byte, 8 bytes, and 4 bytes, the alignment requirement of the structure will be 8 bytes. The compiler will figure this out automatically when the structure is defined. (Technically, the C standard might permit the compiler to give the structure an even greater alignment—I do not see any rule against it—but that is not done in practice.)

Then, whenever the C implementation reserves memory for a structure object (as when you define an object of that type, such as struct foo x), it will ensure the memory is aligned as required for that structure. That results in the alignment requirements of the members being satisfied too. When a program allocates memory with malloc, the returned memory is always aligned as necessary for any object of the requested size.

(If you do any “funny stuff” in a program to set your own memory locations for objects, such as placing one in the middle of memory allocated with malloc, you are responsible for getting the alignment right.)

Further, the structure will be padded at the end if necessary so that its total size is a multiple of that alignment requirement. Then, in an array of those structures, each successive element of the array will begin at a properly aligned location too.

Understanding Structure Padding in C

In the case of x, it contains a double which (in your case) has size 8. That means that the structure as a whole needs to be a multiple of that size in order for an array of x to be properly aligned.

Since arrays are contiguously allocated, each member of the array comes immediately after the prior one in memory. If x had size 10, then for an array the second element would have the A member at offset 10. For proper alignment, each array member needs to start at a multiple of the size of the largest element. So the structure contains padding at the end to accomplish this.

C structure padding problems

This is not a safe operation. The compiler will add padding in an implementation defined manner.

Generally speaking, a member of a given size will be aligned on an offset that is a multiple of that size.

Given the typical way padding is done, this struct will most likely be 16 bytes in size. The physical layout will most likely (but not necessarily) look like this:

struct something {
uint32_t a; // offset 0
uint8_t b; // offset 4
// 1 byte padding
uint16_t c; // offset 6
uint32_t x; // offset 8
uint16_t y; // offset 12
uint8_t z; // offset 14
// 1 byte padding
};

Don't use magic numbers. Intead, use the sizeof operator.

struct something *s = malloc(sizeof(struct something));

EDIT:

If you want to increase the chances that your struct is laid out a particular way, see this guide to structure packing. If you follow the practices here, there's a good chance (but not 100%) that your struct will be laid out in memory the way you expect.

For gcc, you can use __attribute__((packed)) on a struct to remove padding from a struct. Doing so however may incur a performance penalty or could cause a page fault. The -Wpadded and -Wpacked options can also tell you more regarding padding.

structure padding on 64bit machine

The rule for alignment (on x86 and x86_64) is generally to align a variable on it's size.

In other words, 32-bit variables are aligned on 4 bytes, 64-bit variables on 8 bytes, etc.

In your second case, 4 bytes of padding are added between

uint32_t var3;
uint64_t var5;

to get var5 to align on 8 bytes.

For this reason it is better to order data members from largest to smallest (but it's not that simple due to data locality, readability etc.).

Structure Padding

A char type can be accessed efficiently on any address boundary, so no padding is necessary.

How structure padding is works with respect to largest size member in C?

How structure padding is works with respect to largest size member in C?

Padding is fundamentally determined by the alignment requirements of the members, not solely by their sizes. Each complete object type has an alignment requirement, which is some number A such that the address of the object must always be a multiple of A. Alignment requirements are always powers of two.

An object’s size is always a multiple of its alignment requirement, but the alignment requirement is not always equal to the size. For example, an eight-byte double might have four-byte alignment in some C implementations. Alignment requirements typically arise out of hardware considerations, and a system might process eight-byte objects in four-byte chunks whenever it is loading it from memory or storing it to memory, so that hardware would not care about eight-byte alignment even for eight-byte objects. A C implementation designed for that system could make the alignment requirement for an eight-byte double be just four bytes.

For your examples, we will use alignment requirements of one byte for char, four bytes for a four-byte float, and eight bytes for an eight-byte double.

In case 1:

typedef struct{
double A; //8-byte
char B; //1-byte
char C: //1-byte
} Test1;

The structure will always start at the required alignment boundary, because the compiler will give the structure itself an alignment requirement equal to the strictest alignment requirement of any of its members. (Greater than is also allowed by the C standard, but this is not typical in practice.) Then the double A occupies eight bytes. At that point, the char B is at an allowed place, because its alignment requirement is only one byte, so any address is allowed. And char C is also okay. So far, the structure is 10 bytes long. Finally, the structure needs to have an eight-byte alignment so that it can always satisfy the alignment requirement of the double, so the structure’s total size has to be a multiple of eight bytes. To accomplish this, we insert six bytes of padding at the end, and the total structure size is 16 bytes.

In case 2:

typedef struct{
int A; //4-byte
double B; //8-byte
float C; //4-byte
} Test2;

int A starts at offset four. Then double B needs to start at a multiple of eight bytes, so four bytes of padding are inserted. Now we are up to 16 bytes: Four for int A, four for padding, and eight for double B. Then float C is at an okay position. It adds four bytes, and we are up to 20 bytes. The structure size needs to be a multiple of eight bytes, so we add four bytes of padding, making 24 bytes total.

In case 3:

typedef struct{
double A; //8-byte
int B; //4-byte [Typo fixed; was "Int".]
float C; //4-byte
} Test3;

double A is eight bytes, and then int B adds four bytes. Now we are at 12 bytes. That is okay for float C, because its alignment requirement is four bytes, and 12 is a multiple of four. This float adds four bytes to the structure, so the size is now 16 bytes. That is okay for the structure’s alignment requirement, eight bytes, because 16 is a multiple of eight. So we do not need to add any padding, and the total structure size is 16 bytes.

Here is the method that compilers commonly use to determine padding in structures:

  • Each member in the structure has some size s and some alignment requirement a.
  • The compiler starts with a size S set to zero and an alignment requirement A set to one (byte).
  • The compiler processes each member in the structure in order:
  1. Consider the member’s alignment requirement a. If S is not currently a multiple of a, then add just enough bytes S so that it is a multiple of a. This determines where the member will go; it will go at offset S from the beginning of the structure (for the current value of S).
  2. Set A to the least common multiple1 of A and a.
  3. Add s to S, to set aside space for the member.
  • When the above process is done for each member, consider the structure’s alignment requirement A. If S is not currently a multiple of A, then add just enough to S so that it is a multiple of A.

The size of the structure is the value of S when the above is done.

Additionally:

  • If any member is an array, its size is the number of elements multiplied by the size of each element, and its alignment requirement is the alignment requirement of an element.
  • If any member is a structure, its size and alignment requirement are calculated as above.
  • If any member is a union, its size is the size of its largest member plus just enough to make it a multiple of the least common multiple1 of the alignments of all the members.

For elementary types (int, double, et cetera), the alignment requirements are implementation-defined and are usually largely determined by the hardware. On many processors, it is faster to load and store data when it has a certain alignment (usually when its address in memory is a multiple of its size). Beyond this, the rules above follow largely from logic; they put each member where it must be to satisfy alignment requirements without using more space than necessary.

Footnote

1 I have worded this for a general case as using the least common multiple of alignment requirements. However, since alignment requirements are always powers of two, the least common multiple of any set of alignment requirements is the largest of them.



Related Topics



Leave a reply



Submit