获取位字段结构成员的大小

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

我已经定义了一个结构:

struct mystruct {
    uint32_t onebyte   :  8;
    uint32_t twobytes  : 16;
    uint32_t threebits :  3;
};

我知道C将位字段定义为至少与指定的宽度相同,但编译器可能使用更多内存(例如,在这种情况下为3 * 4字节)。但是,设置的宽度是保证的最小值,如果值超出相应的范围,应用程序可能仍然可以正常工作。

要运行一些调试断言,我希望我的代码在设置成员值之前检查值是否超出允许的范围:

assert(someval < (1 << sizeofbitfieldmemberinbits(((mystruct*)NULL)->threebits)));

对于这个特定的情况,在没有任何sizeof()调用的情况下使用稍微不同的方法可能是一个可行的解决方案,但我不确定这是否可以保证工作:

assert(someveal <= ((mystruct){.threebits = -1}).threebits);

无论如何,有没有办法以位(或至少以字节为单位)确定C结构的位字段成员的保证最小大小?

我正在寻找像sizeofbitfieldmemberinbits()这样的表达式,可以由编译器在构建时计算(如((mystruct){.threebits = -1}).threebits可以评估为0x7)。

编辑:正如John Bollinger所指出的,为位字段成员分配的内存可能大于指定的位数,但成员永远不能保存大于(1 << #bits) - 1的值。但是,当我尝试设置超出范围的值时,它将被隐式截断(在运行时)。通过断言,我想检查不仅可能发生这种截断的情况,而是实际发生的情况。

c bit-fields
2个回答
2
投票

我正在寻找像sizeofbitfieldmemberinbits()这样的表达式,可以在构建时由编译器计算

您所描述的标准术语是“constant expression”:

可以在转换期间而不是运行时期间评估常量表达式,并且因此可以在常量可以在任何地方使用。

(C2011,6.6 / 2)

接下来,您将阐明要使用此类常量表达式的目的:

通过断言,我想检查不仅可能发生这种截断的情况,而是实际发生的情况。

但请注意

  1. 为此,位域的大小是次要的。你真正想要的是最大可表示的值。对于签名类型的位域,也许你想要最小值。
  2. 实际上,您不需要常量表达式来使用常规断言,例如您演示(而不是静态断言)。常规断言中的表达式在运行时进行评估。
  3. 另一方面,一些不满足标准的常量表达式定义的表达式仍然可以通过某些实现在转换(编译)时计算。

点(2)和(3)对你来说是幸运的,因为位域具有不能直接表达的第二类类型。在主机结构对象的上下文之外没有任何位域类型的值,并且没有可以表示位域的有效类型的类型名称。这意味着没有常量表达式可以计算位域成员的位数或最大值,除非它包含该成员的先验知识,因为结构(包括结构文字)不在可能出现在合适的操作数中。常数表达式:

算术常量表达式应具有算术类型,并且只能具有整数常量,浮点常量,枚举常量,字符常量,结果为整数常量的sizeof表达式和_Alignof表达式的操作数。算术常量表达式中的强制运算符只能将算术类型转换为算术类型,除非作为sizeof_Alignof运算符的操作数的一部分。

(Qazxswpoi)


毕竟,我认为这个问题可以归结为:

我不确定这是否可以保证:

C2011 6.6/8

对于无符号位域,例如assert(someveal <= ((mystruct){.threebits = -1}).threebits); ,它保证在C99或更高版本中工作。早期版本的C没有复合文字或指定的初始化器,但是,即使在今天,您可能遇到的一些C实现也不符合C99。在这样的实现中,您可能只需要定义一个(可能是mystruct.threebits,也许是const)实例,在其中记录限制...

static

...然后与其成员进行比较:

static const struct mystruct mystruct_limits = { -1, -1, -1 };

请注意,struct member初始值设定项适用于在简单赋值中应用的相同转换,因此只要成员具有无符号类型,-1s作为初始化值就可以很好地定义为具有所需效果。

另请注意,虽然assert(someveal <= mystruct_limits.threebits); 是出于此目的所希望的,但它直到C99才被标准化。不过,在C99之前这是一个非常常见的扩展,并且你不太可能遇到拒绝const的C编译器而不是拒绝复合文字的编译器。


0
投票

有没有办法确定C结构的位字段成员的保证最小大小(以位为单位)

我想检查不仅可能发生这种截断的情况,而且实际上是这样。

const是不够的,因为它的相关代码在运行时肯定不存在。

检查字段的最大值。当字段是某些无符号类型时很容易做到。

assert()

产量

#include <inttypes.h>
#include <stdio.h>

int main(void) {
  struct mystruct {
    uint32_t onebyte :8;
    uint32_t twobytes :16;
    uint32_t threebits :3;
  };
  struct mystruct obj;

  for (int test = 0; test < 20; test++) {
    unsigned n = rand() % 10;

    // I want to check for cases where such truncation not just might occur,
    //  but when actually does.
    if (n > (struct mystruct) {.threebits = -1}.threebits) {
      printf("Truncation will occur, %u\n", n);
    }
    obj.threebits = n;
  }
  return obj.threebits;
}
© www.soinside.com 2019 - 2024. All rights reserved.