【发布时间】:2013-09-10 03:47:04
【问题描述】:
以下代码是否保证正常终止并成功?
#include <assert.h>
struct foo_s {
union {
struct {
unsigned a : 10;
unsigned : 6;
};
struct {
unsigned : 10;
unsigned b : 6;
};
struct {
unsigned : 10;
unsigned c : 6;
};
};
};
int main () {
struct foo_s f;
f.a = 0;
f.b = 1;
assert(f.a == 0);
return 0;
}
在回答不同的question 时,提出了分配给还包含未命名位字段的结构中的命名位字段的可能性,这可能会导致将任意数据写入这些位。 C.11 §6.7.2.1 ¶12 状态:
没有声明符但只有冒号和宽度的位域声明表示 未命名的位域。
我对此的理解是,未命名的位域只是一个常规位域,唯一的区别是这些位中的值不能直接通过名称获得。是否允许使用“as-if”逻辑推断实现并在这些位中分配任意数据?
【问题讨论】:
-
几乎所有与位字段有关的“实现定义”行为都有很多。为什么你需要冒险?为什么不只拥有一个不包含未命名位字段的结构呢?当然,分配给联合的一个部分并从另一个部分读取也是不明确的(并且对
.a和.b的引用是对联合的不同(匿名)成员的引用。 -
Unnamed 位域在运行时的内容是不可预测的,所以 NO 不能保证正常且成功地终止。
-
@JonathanLeffler:使用位域的正常原因都是基于在低级事物上定义更高级别的接口(例如协议头中的字段)。这不仅在代码中有用,而且在调试器中检查数据时也很有用。但是,我想抛开这个问题,专注于语义是否定义明确。
-
@Dayalrai:如果这些位从未初始化,我同意。但是如果这些位被初始化(我给出了一种方式,但另一种方式是
memset()),这些位是否仍然不可预测? -
@jxh 我看到了泥潭。 C.11 §6.7.2.1 ¶12 note 126 说“一个未命名的位域结构成员对于 padding 以符合外部强加的布局很有用。”如果实现认为这是真正的 padding,那么
f.b = 1可能会搞砸f.a。 OTH “结构对象中可能有未命名的填充,但不在其开头。”所以看起来你的断言“未命名的位域只是一个常规的位域”具有可信度。 (我没有使用过,也没有经常看到未命名的位字段,所以没有经验。我给他们起假名。)
标签: c language-lawyer c11