新闻组:comp.lang.c
发件人: Clive D.W. Feather
主题: 回复:征求对 C-FAQ 提交稿的批评意见
日期: 1994 年 9 月 22 日星期四 13:08:17 GMT
消息 ID: <CwJ8Hu.8y6@scone.london.sco.com>

在文章 <35qdf0$7iq@netaxs.com> 中,Eric Raymond 说道:
> 每个
> 连续的位字段组的第一个成员通常是字对齐的,所有后续的
> 位字段会连续地打包到后续的字中(尽管 ANSI C 只要求后者
> 适用于小于字大小的位字段组)。

错误。ISO C(请注意名称的准确性)要求第一个位字段必须放入某个可寻址的对象中,但没有要求它必须是“字”(因此,在 32 位系统上,一个 11 位字段可能会放入一个半字中)。如果后续字段能够放入同一个对象中,那么它必须放在那里。如果不能,它可以跨越两个对象,或者放入一个新的对象中。因此,

    int a : 11;
    int b :  2;
    int c : 11;
    int d :  7;

可以打包为

    32-bit object: a, b, c, d

或者打包为

    16-bit object: a, b
    16-bit object: c
    16-bit object: d

或者打包为

    16-bit object: a, b, 3 bits of c
    16-bit object: 8 bits of c, d

> Q: 在结构体或数组中,我如何确定一个类型的“真实大小”(包括尾部填充)?
> A: 将其表观大小向上舍入到其对齐方式的倍数。

在结构体中,

    offsetof (structure, next field) - offsetof (structure, field)

    sizeof (structure) - offsetof (structure, last field)

数组中没有填充。

> A: 将其表观大小向上舍入到其对齐方式的倍数。

不一定。填充可能取决于后面的内容。

> (假设是 32 位架构,除非另有说明,否则 long=4,int=4,short=2,char=1 均为常规 C 大小)
> (假设是 32 位架构,除非另有说明,否则 long=4,int=4,short=2,char=1 均为常规 C 大小)
> (假设是 32 位架构,除非另有说明,否则 long=4,int=4,short=2,char=1 均为常规 C 大小)

并假设指针大小为 4。

> (4) struct {char *; short; long;} 将在 short 之后有一个半字的填充
> short 之后有一个半字的填充

或者之前。在大端机上,在低位半字中访问该半字可能更容易。

> Q: 如何完全控制结构体的位级布局?
> A: 这就是位字段的用途。将所有成员声明为位字段。
> 结构体可能仍然有不可见的尾部填充(除非你的最后一个
> 位字段正好填满最后一个机器字),但在现代
> 架构上,这将消除所有其他填充,并让你对声明部分的位布局
> 完全控制(尽管访问时间会显著增加)。然而,ANSI 并不*保证*这种
> 良好的行为,所以要小心陷阱。
> 好的行为,所以要小心陷阱。

首先,当字段不能精确匹配时,可能存在填充。其次,你仍然不能保证每个“可寻址对象”内部位字段的顺序。

> 在一些非常老的 36 位字导向架构上,一些实现不佳的 C 编译器上,即使这样也可能不够;一个跨越
> 越过字边界的位字段可能会强制下一个位字段从
> 下一个字的开头开始,留下高达 35 位的不可见间隙。
> 下一个字的开头开始,留下高达 35 位的不可见间隙。

或者在现代架构上实现良好的编译器上,这些编译器选择不去费力地将位字段分割到字边界。

> 在这些机器上,你唯一的选择是将结构体声明为单个
> char 数组,并在 C 语言中自己进行字段访问。

而且你仍然不知道字内位的顺序相对于你正在遵循的外部格式。这无法以严格兼容的方式解决。

-- 
Clive D.W. Feather     | Santa Cruz Operation    | If you lie to the compiler,
clive@sco.com          | Croxley Centre          | it will get its revenge.
Phone: +44 1923 813541 | Hatters Lane, Watford   |   - Henry Spencer
Fax:   +44 1923 813811 | WD1 8YN, United Kingdom | <= NOTE: NEW PHONE NUMBERS