C 怎么可能 unsigned int 只需要两个字节?

问题描述

我正在玩指针,我注意到一件奇怪的事情。

我有一个结构如下:

typedef struct list_element_struct {
    uint32_t x; 
    uint32_t y; 
    uint32_t z; 
    struct list_element_struct *next; 
    }list_element;

据我所知,unsigned int 的大小是 4 个字节,一个指针的大小是 8 个字节。这里也有 8 个字节对齐,所以这个结构体的大小是 24 个字节。

我已经使用 list_element els[5]; 初始化了上述结构对象的列表,并使用 memset(els,5*sizeof(list_element)); 将其中的每条数据设置为 0

现在我正在尝试使用这些代码查看它们的内存位置:

printf("%p start location of els\n",&(els));
printf("%p start location of els->x\n",&(els->x));
printf("%p start location of els->y\n",&(els->y));
printf("%p start location of els->z\n",&(els->z));
printf("%p start location of els->next(pointer)\n",&(els->next));
printf("%p start location of els+1\n",&(els[1]));

我打印出来的是:

0x7ffeeba4a970 start location of els
0x7ffeeba4a970 start location of els->x
0x7ffeeba4a974 start location of els->y
0x7ffeeba4a978 start location of els->z
0x7ffeeba4a980 start location of els->next(pointer)
0x7ffeeba4a988 start location of els+1

这就是奇怪的事情。为什么 els->z 只需要两个字节?它真的应该像 x 和 y 这样的 4。

解决方法

那些数字是十六进制的。 0x7ffeeba4a9780x7ffeeba4a980 的区别不是 2,而是 8。

为了避免您的下一个问题,它是 8 而不是 4 的原因可能是由于对齐要求。许多 64 位系统要么要求要么倾向于将它们的 8 字节指针与 8 字节边界对齐,即对齐为 8 的倍数的地址(因此它们的最低有效十六进制数字是 8 或 {{ 1}})。因此,编译器在 0z 之间留下了 4 个字节的填充来实现这一点。

,

地址显示为十六进制值

0x7ffeeba4a978 start location of els->z
0x7ffeeba4a980 start location of els->next(pointer)

所以(考虑最后两个十六进制数字)你有

  0x80
-
  0x78
  ====
     8

因为 0x80 等于 0x70 + 十进制 16 或十六进制 0x10

升序中的十六进制数字是

0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F and the next number is 0x10.

编译器在数据成员 z 之后放置了一个等于 4 个字节的填充以进行对齐。