C语言 决定两个结构构件之间的距离的因素


#include‬ <stdio.h>
struct test
{
    unsigned int x;
    long int y;
    unsigned int z;
};
int main()
{
    struct test t;
    unsigned int *ptr1 = &t.x;
    unsigned int *ptr2 = &t.z;
    printf("%d", ptr2 - ptr1);
    return 0;
}

该程序的输出在我的系统上4,为什么我得到这个结果而不是2ptr2 - ptr1语句是否正确,因为ptr1ptr2来自指向同一结构项成员的指针?

此输出4的原因与每种类型的大小以及结构填充和对齐方式有关。

在我的系统上,sizeof(unsigned int)是 4,sizeof(long int)是 8,sizeof(struct test)是 24。 因此,为了确保 64 位字段位于 64 位边界上,结构的物理布局如下所示:

struct test
{
    unsigned int x;     // 4 bytes
                        // 4 bytes padding
    long int y;         // 8 bytes
    unsigned int z;     // 4 bytes
                        // 4 bytes padding
};

因此,当您取x的偏移量和z的偏移量之间的差值时,有16个字节的差异。 由于我们正在做指针减法,因此差值的值是{字节偏移差}/{元素大小}。 所以我们有 16(字节差(/4(sizeof(无符号整数((== 4。

如果sizeof(long int)是 4,那么结构体的布局可能会是这样的:

struct test
{
    unsigned int x;     // 4 bytes
    long int y;         // 4 bytes
    unsigned int z;     // 4 bytes
};

在这种情况下,输出将为 2。

请注意,虽然结构成员的顺序定义为顺序,但填充的布局是实现定义的。 编译器可以根据需要自由填充。

从C标准第6.7.2.1节:

13 在结构对象中,非位字段成员和位字段所在的单元具有以下地址: 增加声明顺序。 指向 结构对象,适当转换,指向其初始 成员(或者,如果该成员是位字段,则到单元 它所在的位置(,反之亦然。 可能有未命名的 在结构对象中填充,但不在其开头填充。

15结构或联合的末端可能有未命名的填充。