我有两个结构,如下所述。注释指定数据成员的大小和编译器将扩充的填充值。
#include <stdio.h>
#include <stdint.h>
typedef struct peer_msg_hdr
{
char type; /**< 1 */
/**< pad[3] */
uint32_t id; /**< 4 */
uint64_t timestamp; /**< 8 */
} PEER_MSG_HDR; /**< 16 */
typedef struct peer_msg
{
PEER_MSG_HDR hdr; /**< 16 */
uint16_t listen_port; /**< 2 */
/**< pad[2] */
uint32_t num_nodes; /**< 4 */
uint32_t num_proc; /**< 4 */
} PEER_MSG;
int main()
{
printf("%lu\n", sizeof(PEER_MSG));
return 0;
}
现在在一台x86_64主机中,首先我计算PEER_MSG的大小。原来是32岁。接下来,如果我在 gcc 中使用 -m32 选项计算大小,则大小为 28。
这两者之间的差异出现在最后一个数据成员 num_proc 之后的填充中。在 -m32 选项编译的情况下,没有填充。但是如果没有 -m32 选项,则有一个 4 个字节的填充(将整个结构对齐为 8 个字节,因为最宽的数据成员大小为 8 个字节(uint64_t 时间戳))。
我的问题是:使用 -m32 选项,uint64_t 的大小仍然是 8 个字节,但结构PEER_MSG的对齐方式是 4 个字节,这与填充的一般规则相矛盾(结构对齐方式应等于其最宽数据成员的对齐方式)。那么这里使用 -m32 选项填充的编译器规则是什么?
在 32 位机器上,处理字大小为 4 个字节,因此结构根据 28 字节的大小对齐,这就是为什么你得到 PEER_MSG 的大小为 28 字节。在 64 字节的系统上,由于处理字的大小为 8 个字节,因此PEER_MSG的大小为 32 个字节。
当您指定 -m32 选项时,编译器将假定最终可执行文件将在 32 字节系统上运行,因此会适当地进行填充。
我的问题是:使用 -m32 选项,uint64_t的大小仍然是 8 个字节,但结构PEER_MSG的对齐方式是 4 个字节,
您的结构对齐点应等于其最宽数据成员的对齐
是错误的。