当前位置: C语言 -- 基础 -- 声明

声明(四)

1.1、位字段

由指定数量的位(如果存在符号位,包括符号位。)构成的结构成员或者联合成员称为位字段(bit-field),位字段的语法格式如下所示:

declaratoropt : constant-expression

其中declarator是声明符,opt表示可选,constant-expression是指定位字段宽度的非负整数常量表达式,取值范围为[0, sizeof(type)×CHAR_BIT]

struct s{
    unsigned hour : 5;
    unsigned minute : 6;
    unsigned second : 6;
};

地址运算符(&)不能用于位字段对象;不存在指向位字段对象的指针或者位字段对象数组。

struct s1{
    int arr[3] : 12;    //非法。
    double d;
};

struct s2{
    int i : 5;
    double d;
} ss;

int *ptr = &ss.i;   //非法。

位字段解释为由指定位数构成的有符号或者无符号整数类型。如果类型说明符是int或者定义为inttypedef名,位字段是有符号类型还是无符号类型将由实现定义。如果0或者1存储到bool类型的非0宽度的位字段,位字段值与存储值相等。bool类型位字段具有bool类型对象的语义。

struct s{
    int i;
    bool b : 1;
} ss;

ss.b = 5;   //ss.b的值为1。

实现可分配足够大的可寻址存储单元来存储位字段。如果空间足够,结构中紧跟位字段的下一个位字段应存储到同一单元的相邻位中;如果空间不足,下一个位字段是存入下一个单元,还是与相邻单元重叠,将由实现定义。位字段在同一单元内的分配顺序(是高阶到低阶,还是低阶到高阶。)由实现定义。可寻址存储单元的对齐方式是未指定的。

//假设int类型对象占32个位。
struct s{
  int i;
  int a : 10;
  int b : 10;
  int c : 10;
  int d : 6;  //位字段d的存储是实现定义行为。
};

如果位字段声明中不存在声明符,只存在:符号和常量表达式,则表示该位字段是未命名位字段(unnamed bit-field)。宽度为0的位字段,应为未命名位字段,其表示不再将任何位字段填充到前一个位字段所在的单元内。未命名位字段可用于填充,以满足所需的对齐要求。

// struct s1类型占12个字节,96个位,共3个存储单元,
// i、a、b分别位于不同存储单元。
struct s1{
  int i;
  int a : 5;
  int   : 0;
  int b : 7;
};

// struct s2类型占8个字节,64个位,共2个存储单元,
// i占一个存储单元,a、b位于另一个存储单元。
struct s2{
  int i;
  int a : 5;
  int b : 7;
};

1.2、匿名结构

类型说明符是无标记结构说明符的结构称为匿名结构(anonymous structure)。如果结构成员是匿名结构或者匿名联合,匿名结构或者匿名联合的成员认为是包含匿名结构或者匿名联合的结构的成员;如果匿名结构成员或者匿名联合成员包含的结构或者联合也是匿名结构或者匿名联合,上述规则递归适用。

struct s{
  struct {  //匿名结构。
    int a;
    double b;
  };

  struct {  //匿名结构。
    int c;
    double d;
  } s2;

  struct {  //匿名结构。
    struct {  //匿名结构。
      int e;
      double f;
    };
  };
}ss;

ss.a = 5;     //合法。
ss.b = 3.14;  //合法。

ss.s2.c = 3;    //合法。
ss.s2.d = 1.23; //合法。

ss.c = 3;     //非法。
ss.d = 1.23;  //非法。

ss.e = 7;   //合法。
ss.f = 5.7; //合法。