Kartik
Kartik

Reputation: 53

How can size of a structure be a non-multiple of 4?

I'm new to structures and was learning how to find the size of structures. I'm aware of how padding comes in to play in order to properly align the memory. From what I've understood, the alignment is done so that the size in memory comes out to be a multiple of 4. I tried the following piece of code on GCC.

struct books{
  short int number;
  char name[3];
}book;
printf("%lu",sizeof(book));

Initially I had thought that the short int would occupy 2 bytes, followed by the character array starting at the third memory location from the beginning. The character array then would need a padding of 3 bytes which would give a size of 8. Something like this, where each word represents a byte in memory.

short short char char

char padding padding padding

However on running it gives a size of 6, which confuses me.

Any help would be appreciated, thanks!

Upvotes: 1

Views: 1604

Answers (3)

Gardener
Gardener

Reputation: 2660

Generally, padding is inserted to allow for aligned access of the internal elements of the structure, not to allow the entire structure to be a size of multiple words. Alignment is a compiler implementation issue, not a requirement of the C standard.

So, the char elements which are 3 bytes in length, need no alignment because they are byte elements.

It is preferred, though not required, that the short element needs to be aligned on a short boundary -- which means an even address. By aligning it on a short boundary, the compiler can issue a single load short instruction rather than having to load a word, mask, and then shift.

In this case, the padding is probably, but not necessarily, happening at the end rather than in the middle. You will have to write code to dump the address of the elements to determine where padding is taking place.

EDIT: . As @Euguen Sh mentions, even if you discover the padding scheme that the compiler is using for the structure, the compiler could modify that in a different version of the compiler.

It is unwise to count on the padding scheme of the compiler. There are always methods to access the elements in such a way that you do not guess at alignments.

The sizeof() operator is used to allow you to see how much memory is used AND to know how much will be added to a ptr to the structure if that pointer is incremented by 1 (ptr++).

EDIT 2, Packing: Structures may be packed to prevent padding using the __packed__ attribute. When designing a structure, it is wise to use elements that naturally pack. This is especially important when sending data over a communications link. A carefully designed structure avoids the need for padding in the middle of the strucuture. A poorly designed structure which is then compiled with the __packed__ attribute may have internal elements that are not naturally aligned. One might do this to ensure that the structure will transmit across a wire as it was originally designed. This type of effort has diminished with the introduction of JSON for transmission of data over a wire.

Upvotes: 4

SKi
SKi

Reputation: 8476

Usually compilers follow ABI of the target architecture. It defines alignments of structures and primitive datatypes. And that affects to needed padding and sizes of structures. Because alignment is multiple of 4 in many architectures, size of structures are too.

Compilers may offer some attributes/options for changing alignments more or less directly.

For example gcc and clang offers: __attribute__ ((packed))

Upvotes: 0

cmdLP
cmdLP

Reputation: 1856

#include <stdalign.h>
#include <assert.h>

The size of a struct is always divisible by the maximum alignment of the members (which must be a power of two). If you have a struct with char and short the alignment is 2, because the alignment of short is two, if you have a struct, only out of chars it has an alignment of 1.

There are multiple ways to manipulate the alignment:

alignas(4) char[4]; // this can hold 32-bit ints

This is nonstandart, but available in most compilers (GCC, Clang, ...):

struct A {
    char a;
    short b;
};

struct __attribute__((packed)) B {
    char a;
    short b;
};

static_assert(sizeof(struct A) == 4);
static_assert(alignof(struct A) == 2);

static_assert(sizeof(struct B) == 3);
static_assert(alignof(struct B) == 1);

Upvotes: 2

Related Questions