-1

I already referred to this question, but still can't find an answer for this following case. Why does the padding not apply for the case of test1?

#include <stdio.h>

typedef unsigned short u16;
typedef unsigned char u8;
typedef struct
{
    u8 a[5];
    u8 b;
    u8 c;
} test1;

typedef struct
{
    u8 a[5];
    u16 b;
} test2;

int main(void) {
    test1 t1;
    test2 t2;
    printf("t1 = %d\n", sizeof(t1));
    printf("t2 = %d\n", sizeof(t2));
    return 0;
}

Output:
t1 = 7
t2 = 8

Update

After the answers from @ryyker and @Ajay Brahmakshatriya, i made another test code and it seems the answers don't apply to this case... If the padding size is 3, because the size of type test1 is 3, why does the size of test2 not 9 instead of 7?

#include <stdio.h>

typedef unsigned short u16;
typedef unsigned char u8;
typedef struct
{
    u8 a;
    u8 b;
    u8 c;
} test1;

typedef struct
{
    test1 a[2];
    u8 b;
} test2;

int main(void) {
    test1 t1;
    test2 t2;
    printf("t1 = %d\n", sizeof(t1));
    printf("t2 = %d\n", sizeof(t2));
    return 0;
}

Output:
t1 = 3
t2 = 7
scmg
  • 1,904
  • 1
  • 15
  • 24
  • Because the alignment requirement of an array type is the same as the alignment requirement of its element type. – Ian Abbott Feb 04 '20 at 11:57
  • First the compiler finds the type which needs more space and keeps this space as base and padds other types according to that. – RaHuL Feb 04 '20 at 12:44
  • `typedef unsigned short u16;`? Why are you creating your own type? Just use the standard `uint16_t` if you want a 16-bit unsigned integer variable. – Andrew Henle Feb 04 '20 at 12:52
  • @scmg - So far you have not responded to any of the comments, or the answers. Has any of this helped you? Any questions?... – ryyker Feb 04 '20 at 17:56
  • @AndrewHenle `uint16_t` is not a basic type in my pov, you need to include a header for that. And it's much faster to type if you don't have auto-completion. – scmg Feb 05 '20 at 08:46
  • @scmg *uint16_t is not a basic type in my pov* Then you shouldn't be assuming `unsigned short` is 16 bits. – Andrew Henle Feb 05 '20 at 10:37
  • @AndrewHenle yes, but i am sure on the system where i test the code, `unsigned short` is 16 bits – scmg Feb 05 '20 at 11:33
  • I think it has been gone too far from my question. It is anyway only a test code, in which i tried to make it as much similar to the real implementation as possible, as well as to hide real information as much as possible. How do you use `uint16_t` if you have to use C90 and can't include `stdint.h`? The `stdio.h`and `printf` are also there just in case anyone wants to try the code in their IDE, they are not allowed to exist in my real code too. – scmg Feb 05 '20 at 14:05

2 Answers2

0

The alignment requirement of a struct is greater than equal to the alignment requirement of each its member. Also, the alignment requirement of an array is the same as that of its elements.

If the alignment requirement of u8 is 1 byte and the alignment requirement of u16 is 2 bytes, the alignment requirement of test1 would be at least 1 byte and that of test2 would be at least 2 bytes.

Since the alignment requirement of test2 is 2 bytes, its size should also be a multiple of 2 bytes (this way if you declare an array of the struct, all the elements of the array can be aligned properly).

The sum of sizes of elements of test2 is 7 bytes. The closest multiple of 2 is 8 bytes. For test1, since the alignment requirement is only 1 byte, 7 is an acceptable size.

Finally, the implementations are allowed to add any amount of padding to the structs as long it satisfies all the above constraints. So there is no right way to answer the question "Why is the size of this struct not equal to what I calculated?". What I have here is a likely rationale as to why your implementation chose the current sizes.

Ajay Brahmakshatriya
  • 8,993
  • 3
  • 26
  • 49
0

Why does the padding not apply for the case of test1... Because bytes are the smallest natural memory segment, and in the case of the first struct the only type used, the compiler sets memory alignment for this struct at one byte segments. None of the members bump up against that natural alignment. Therefore padding is not required.

In the second struct definition there is one u16 type, and an odd number of bytes (5) stored in the array member. The u16 member causes alignment boundaries ( | ) to be (by default) two bytes:

The first struct could be viewed as a series of byte memory locations, with 1 byte alignment:

|.......|.......|.......|.......|.......|.......|.......| ( 7-bytes )
   a[0]    a[1]    a[2]    a[3]    a[4]     b       c

The second struct, with the u16 member, uses 2-byte alignment: (thus also results in padding.)

|...............|...............|...............|..............| (8-bytes )
   a[0]   a[1]    a[2]    a[3]    a[4] (padding)       b     

Note, default alignment boundaries can be modified by using a pragma statement. For example pragma pack(1) forces the alignment boundary to 1 byte. This would effectively place b adjacent to a[4] in memory, and would make the second struct the same size as the first.

|.......|.......|.......|.......|.......|.......|.......| ( 7-bytes )
   a[0]    a[1]    a[2]    a[3]    a[4]         b       


pragma pack(1)//force alignment to 1 byte
typedef struct
{
    u8 a[5];
    u16 b;
} test2;
pragma pack()// set packing back to what it was

Even though this question/answer talks about pragma statements, it covers the surrounding concepts, such as the one you are asking about well.

ryyker
  • 22,849
  • 3
  • 43
  • 87