c - 为什么sockaddr_storage 结构定义为它定义的方式?

标签 c unix sockets

下面是 sockaddr_storage 结构体的定义 (rfc2553)。根据 rfc2553,sockaddr_storage 应该与 64 位边界对齐,并且它应该能够同时容纳 sockaddr_in 和 sockaddr_in6。 此外,它必须至少有 __ss_family 成员。其余字段由实现定义。

#define _SS_MAXSIZE    128  /* Implementation specific max size */
#define _SS_ALIGNSIZE  (sizeof (int64_t))
                         /* Implementation specific desired alignment */
/*
 * Definitions used for sockaddr_storage structure paddings design.
 */
#define _SS_PAD1SIZE   (_SS_ALIGNSIZE - sizeof (sa_family_t))
#define _SS_PAD2SIZE   (_SS_MAXSIZE - (sizeof (sa_family_t)+
                              _SS_PAD1SIZE + _SS_ALIGNSIZE))
struct sockaddr_storage {
    sa_family_t  __ss_family;     /* address family */
    /* Following fields are implementation specific */
    char      __ss_pad1[_SS_PAD1SIZE];
              /* 6 byte pad, this is to make implementation
              /* specific pad up to alignment field that */
              /* follows explicit in the data structure */
    int64_t   __ss_align;     /* field to force desired structure */
               /* storage alignment */
    char      __ss_pad2[_SS_PAD2SIZE];
              /* 112 byte pad to achieve desired size, */
              /* _SS_MAXSIZE value minus size of ss_family */
              /* __ss_pad1, __ss_align fields is 112 */
};

我的问题是为什么sockaddr_storage是按照上面的方式定义的?为什么不能如下定义?

struct sockaddr_storage {
    sa_family_t  __ss_family;     /* address family */
    char __ss_pad[_SS_MAXSIZE  - sizeof(sa_family_t) ]; //will there be any alignment issue here?
};

最佳答案

您提出的替代方案不会强制整个结构在 8 字节(64 位)边界上对齐,您提到这是 RFC2553 的要求。

一般来说,一个结构采用其任何成员所要求的最严格的对齐方式。由于 sa_family_t 可能是一个 u16_t,它只需要 2 字节对齐,而一个 char 数组最多需要 1 字节对齐,所以你提出的替代方案只需要 2 -字节对齐。 (无论如何,编译器很可能会给它至少 4 字节甚至 8 字节对齐,但您不能确定。)

实际定义的风格是试图确保结构中的每个字节都是某个命名字段的一部分,即编译器不会在字段之间插入任何填充。这是必需的(有点),以便 _SS_PAD2SIZE 有一个可以根据所有其他成员的大小计算的值。

但是,我觉得这个定义相当复杂。我很确定以下内容同样有效,并且更容易理解:

struct sockaddr_storage {
    union {
        sa_family_t u_family;
        uint64_t u_pad[_SS_MAXSIZE / sizeof(uint64_t)];
    } __ss_u;
#   define __ss_family __ss_u.u_family
};

此处, union 获取其最严格对齐成员的对齐要求,然后传播到封闭结构。请注意,在这个版本中,我只有一个必填字段(虽然埋在 union 中)和一个填充数组,它的大小正是我希望整个结构的大小。唯一有点棘手的部分是 __ss_family 的宏定义。宏技巧可能不严格符合 RFC 中的要求,但很少(如果有的话)可以注意到差异。

关于c - 为什么sockaddr_storage 结构定义为它定义的方式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1345109/

相关文章:

linux - 抢占式线程与非抢占式线程

c++ - 错误 : invalid conversion from 'int' to 'std::_Ios_Openmode' |

c - 如何管理 union 和位域

c - 无论 fork() 多少次,父进程仅从其子进程接收到 SIGCHLD 一两次

定制sprintf,值得吗?

linux - 如何使用 find 在 CSH 中复制带前缀的文件?

使用标准 C 库的 C SSL 实现

linux - 如何在写入数据时通过 UDP 套接字发送数据?

c - float 给出非常大的答案(C)

c - 如何使用execve导出环境变量