-3

I know what padding is and how alignment works. Given the struct below:

typedef struct {
char word[10];
short a;
int b;  
} Test;

I don't understand how C interprets and aligns the char array inside the struct. It should be 9 chars + terminator and it should be regarded as the longest like this:

| - _ - _ - _ - _ - word - _ - _ - _ - _ - |
| - a - | - _ - b - _ - | padding the remaining 4 bytes

The "-" represents a byte and "_" separates the bytes. So we have the 10 bytes long word, the 2 bytes long a and the 4 bytes long b and padding of 4 bytes. But when I print sizeof(Test) it returns 16.

EDIT: I got it.

  • 2
    Your explanation and variable names do not match. there's no `c`. – Sourav Ghosh Jan 23 '20 at 14:46
  • Maybe you did a mistake in drawing the memory schema. It contains a-b-c instead of word-a-b. – Roberto Caboni Jan 23 '20 at 14:46
  • 3
    Where do you get padding of four bytes from? Who says this structure needs padding? – Eric Postpischil Jan 23 '20 at 14:49
  • 1
    Sorry for the variable mistake, I edited the question and the question you posted the link to doesn't answer my question. – OscarTheMighty Jan 23 '20 at 14:49
  • 1
    I am not sure the linked question answers this one. But, in short, you have only padding if the following field needs it. A short only needs to be padded to an even address (resp. offset), which you have after an even-sized array. And the int following it needs an offset which is divisible by 4, which it has. And the whole structure only needs to have a length modulo its longest single-type (which is 4), removing the padding need at the end. A length of 16 is very fine. – glglgl Jan 23 '20 at 14:50
  • Aren't the bytes of the char[10] represented on the same line though? And the final result must be a matrix with the same number of columns on each line? And since the char is the longest variable of 10 bytes the other lines also must have 10 columns? – OscarTheMighty Jan 23 '20 at 14:51
  • @OscarTheMighty What lines are you talking about? – glglgl Jan 23 '20 at 14:52
  • Like the 2 lines I represented in my question, the longest variable decides the number of padding bytes for each variable – OscarTheMighty Jan 23 '20 at 14:53
  • @glglgl I must have misunderstood something about how it is stored in the memory, can you draw the memory schema in the answers? – OscarTheMighty Jan 23 '20 at 14:55
  • 1
    There are no lines. A structure contains all of its members, in order in memory (possibly with padding between them), all separate from each other. A union overlaps members. In a union, **all** members are overlapped. To get an aggregate in which some members are laid out separately and some are overlapped, you must use a union containing structures. – Eric Postpischil Jan 23 '20 at 14:57
  • As I specified in the question, I don't understand how it works for char arrays. – OscarTheMighty Jan 23 '20 at 14:59
  • 1
    To get the type you are describing, you would declare it as `typedef union { char word[10]; struct { short a; int b; }; } Test;`. – Eric Postpischil Jan 23 '20 at 15:04
  • 1
    @OscarTheMighty then it means you do not understand it *at all*. The alignment is about *primitives* being at their aligned addresses, and padding inserted to meet these alignment requirements even when the struct is an element of an array. – Antti Haapala -- Слава Україні Jan 23 '20 at 15:08
  • @AnttiHaapala: Their misunderstanding is not about padding. Their misunderstanding is about members of structures being all separate, even if they are arrays or something. – Eric Postpischil Jan 23 '20 at 15:26

3 Answers3

5

In a struct like

struct {
    char word[10];
    short a;
    int b;  
}

you have the following requirements:

  • a needs an even offset. As the char arry before it has an even length, there is no need for padding. So a sits at offset 10.
  • b needs an offset which is dividible by 4. 12 is dividible by 4, so 12 is a fine offset for b.
  • The whole struct needs a size which is dividible by 4, because every b in an array of this struct needs to have the said requirement. But as we are currently at size 16, we don't need any padding.

    WWWWWWWWWWAABBBB |-- 10 --| 2 4 = 16

Compare this with

struct {
    char word[11];
    short a;
    int b;  
}

Here, a would have offset 11. This is not allowed, thus padding is inserted. a is fine with an offset of 12.

b would then get an offset of 14, which isn't allowed either, so 2 bytes are added. b gets an offset of 16. The whole struct gets a size of 20, which is fine for all subsequent items in an array.

WWWWWWWWWWW.AA..BBBB
|--  11 --|1 2 2   4 = 20

Third example:

struct {
    char word[11];
    int b;  
    short a;
}

(note the changed order!)

b is happy with an offset of 12 (it gets 1 padding byte), a is happy with an offset of 16. (no padding before it.)

After the struct, however, 2 bytes of padding are added so that the struct aligns with 4.

WWWWWWWWWW..BBBBAA..
|-- 10 --| 2   4 2 2 = 20
glglgl
  • 89,107
  • 13
  • 149
  • 217
3

In:

struct
{
    char word[10];
    short a;
    int b;  
}

and given two-byte short and four-byte int, the structure is laid out in memory:

Offset Member
     0 word[0]
     1 word[1]
     2 word[2]
     3 word[3]
     4 word[4]
     5 word[5]
     6 word[6]
     7 word[7]
     8 word[8]
     9 word[9]
    10 a
    11 a
    12 b
    13 b
    14 b
    15 b

To get the layout described in the question, where a and b overlap word, you need to use a struct inside a union:

typedef union
{
    char word[10];
    struct { short a; int b; };
} Test;
Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
2

Generally, each variable will be aligned on a boundary of its size.
(unless attributes such as packed are applied)

A complete discussion is on Wikipedia, which says in part:

A char (one byte) will be 1-byte aligned.
A short (two bytes) will be 2-byte aligned.
An int (four bytes) will be 4-byte aligned.
A long (four bytes) will be 4-byte aligned.
A float (four bytes) will be 4-byte aligned.
A double (eight bytes) will be 8-byte aligned on Windows and 4-byte aligned on Linux (8-byte with -malign-double compile time option).
A long long (eight bytes) will be 4-byte aligned.

So your structure is laid out as:

typedef struct {
char word[10];
// Aligned with beginning of structure; takes bytes 0-9

short a;
// (assuming short is 2-bytes)
// Previous member ends on byte 9, this one starts on byte-10.
// Byte 10 is a multiple of 2, so no padding necessary
// Takes bytes 10 and 11

int b;        
// Previous member ends on byte 11, next byte is 12, which is a multiple of 4.  
// No padding necessary
// Takes bytes 12, 13, 14, 15.
} Test;

Total size: 16 bytes.

If you want to play with it, change your word-array to 9 or 11 bytes, or reverse the order of your short and int, and you'll see the size of the structure change.

abelenky
  • 63,815
  • 23
  • 109
  • 159