具有不同类型字段的填充结构

时间:2020-02-04 11:53:51

标签: c padding

我已经提到过Intl.v8BreakIterator,但仍然无法找到以下情况的答案。 为什么填充不适用于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

更新

在来自@ryyker和@Ajay Brahmakshatriya的答案之后,我做了另一个测试代码,看来答案不适用于这种情况...如果填充大小为3,因为类型为{{1} }是3,为什么test1的大小不是9而不是7?

test2

2 个答案:

答案 0 :(得分:0)

结构的对齐要求大于等于其每个成员的对齐要求。另外,数组的对齐要求与其元素的对齐要求相同。

如果u8的对齐要求为1个字节,u16的对齐要求为2个字节,则test1的对齐要求将至少为1个字节,而{{ 1}}至少应为2个字节。

由于test2的对齐要求是2个字节,因此它的大小也应该是2个字节的倍数(这样,如果您声明该结构的数组,则该数组的所有元素都可以正确对齐) 。

test2的元素大小之和为7个字节。 2的最接近倍数是8个字节。 对于test2,由于对齐要求仅为1个字节,因此7是可接受的大小。

最后,只要满足上述所有约束,这些实现就可以向结构中添加任意数量的填充。因此,没有正确的方法来回答“为什么此结构的大小不等于我所计算的大小?”的问题。我在这里可能是关于为什么您的实现选择了当前大小的理由。

答案 1 :(得分:0)

为什么填充不适用于test1 ......因为字节是最小的自然内存段,而对于第一个struct,仅 类型,编译器为此struct 在一个字节段设置内存对齐方式。没有一个成员反对这种自然的统一。因此,不需要填充。

在第二个结构定义中,有一种u16类型,并且在数组成员中存储了奇数个字节(5)。 u16成员导致对齐边界(|)(默认情况下)为两个字节:

第一个结构可以看做是一系列字节存储位置,具有1个字节对齐:

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

具有u16成员的第二个结构使用2字节对齐:(因此也会导致填充。)

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

请注意,可以使用pragma语句修改默认的对齐边界。例如,pragma pack(1)将对齐边界强制为1个字节。这将有效地将ba[4]相邻放置在内存中,并使第二个结构的大小与第一个相同。

|.......|.......|.......|.......|.......|.......|.......| ( 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

尽管this question/answer谈论了pragma语句,但它涵盖了周围的概念,例如您所要求的概念。