初始化位域

问题描述 投票:0回答:2

写作时

struct {
    unsigned a:3, b:2;
} x = {10, 11};

x.b
是否保证为 ANSI C(C89)的
3
?我已经阅读并重新阅读了该标准,但似乎无法找到确切的情况。

例如,“无法用 生成的无符号整数类型以数字为模减少 比可以表示的最大值大一个 结果无符号整数类型。”谈到计算,而不是初始化。而且,位域并不是真正的类型。

此外,(当谈到无符号 t:4 时)“包含 [0,15] 范围内的值”,但这并不一定意味着初始化器必须以 reduced modulo 16 映射到 [0,15] .

Struct 初始化真的是煞费苦心地详细描述了,但我似乎真的无法找到确切的行为。 (当然,编译器就是这样做的。IBM 文档说“当您将超出范围的值分配给位字段时,将保留低阶位模式并分配适当的位。”,但我想知道 ANSI C 是否对其进行了标准化。

c struct initialization bit-fields ansi-c
2个回答
7
投票

“ANSI C”/C89 已经过时 25 年了。因此,我的回答引用了当前的 C 标准 ISO 9899:2011,也称为 C11。


几乎所有与 C 标准中的位域相关的内容都没有明确定义。通常,您不会发现任何明确说明位域行为的内容,但它们的行为是隐式指定的,“在字里行间”。这就是为什么你应该避免使用位字段。

但是,我相信这个特定情况是明确定义的:它应该像任何其他整数初始化一样工作。

您提到的详细结构初始化规则(6.7.9)显示了初始化列表中的文字

11
如何与变量
b
相关。这没什么奇怪的。然后应用的是“简单赋值”,就像你写
x.b = 11;
.

一样

在 C 中进行任何类型的赋值或初始化时,右操作数转换为左操作数的类型。这是由 C11 6.5.16 指定的:

简单赋值(=)中,右操作数的值被转换 赋值表达式的类型并替换存储的值 在左操作数指定的对象中。

在您的情况下,

int
类型的文字11 被转换为unsigned int:2.

的位域

因此,您正在寻找的规则应该在处理转换的章节 (C11 6.3) 中找到。适用的是您在问题 C11 6.3.1.3 中已经引用的内容:

...如果新类型是无符号的,则值被重复转换 比最大值加或减一 以新类型表示,直到值在新类型的范围内 类型。

一个unsigned int:2的最大值是3。比最大值大一是3+1=4。编译器应该从值 11 中重复减去它:

11 - (3+1) = 7    does not fit, subtract once more:
 7 - (3+1) = 3    does fit, store value 3

当然,这与取十进制值 11 的 2 个最低有效位并将它们存储在位域中是完全相同的事情。


2
投票

WRT“speaks about computation, not about initialization”,C89标准明确将赋值和转换规则应用于初始化。它还说:

位域被解释为由指定位数组成的整数类型。

鉴于这些,虽然编译器警告显然是有序的,但标准似乎保证丢弃高位。

© www.soinside.com 2019 - 2024. All rights reserved.