【问题标题】:padding struct with different types of fields使用不同类型的字段填充结构
【发布时间】:2020-05-20 05:58:48
【问题描述】:

我已经提到了this question,但仍然无法找到以下案例的答案。 为什么填充不适用于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,因为test1 类型的大小是3、为什么test2的大小不是9而是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

【问题讨论】:

  • 因为数组类型的对齐要求与其元素类型的对齐要求相同。
  • 首先编译器找到需要更多空间的类型,并将这个空间作为基础,并据此填充其他类型。
  • typedef unsigned short u16;?为什么要创建自己的类型?如果您想要一个 16 位无符号整数变量,只需使用标准 uint16_t
  • @scmg - 到目前为止,您还没有回复任何 cmets 或答案。这些对你有帮助吗?有什么问题吗?...
  • @AndrewHenle uint16_t 在我的 pov 中不是基本类型,您需要为此包含一个标题。如果您没有自动完成功能,输入速度会更快。

标签: c padding


【解决方案1】:

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

如果u8的对齐要求是1个字节,u16的对齐要求是2个字节,那么test1的对齐要求至少是1个字节,test2的对齐要求至少是2个字节字节。

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

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

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

【讨论】:

    【解决方案2】:

    为什么填充不适用于test1的情况...因为字节是最小的自然内存段,并且在第一个struct的情况下只有 em> 类型,编译器设置内存对齐为此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 语句,但它涵盖了周围的概念,例如您要问的那个。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-07-09
      • 2019-11-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-27
      相关资源
      最近更新 更多