简体   繁体   English

获取位域结构成员的大小

[英]Get size of bit-field struct members

I have defined a struct like: 我已经定义了一个类似的结构:

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

I know that C defines bit-fields to be at least as wide as specified, but the compiler may use more memory (eg 3*4 bytes in this case). 我知道C将位字段定义为至少与指定的宽度相同,但是编译器可能会使用更多的内存(例如,在这种情况下为3 * 4字节)。 However, the set width is a guaranteed minimum and if a value exceeds the according range, the application might still work correctly by chance. 但是,设置的宽度是保证的最小值,如果值超出相应范围,则应用程序可能仍然会偶然运行。

To run some debug assertions, I want my code to check whether a value exceeds the allowed range before setting the member value: 要运行一些调试声明,我希望我的代码在设置成员值之前检查值是否超出允许范围:

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

For this specific case it might be a feasible solution to use a slightly different approach without any sizeof() call, but I am not sure if this is guaranteed to work: 对于这种特定情况,使用稍微不同的方法而不进行任何sizeof()调用可能是一个可行的解决方案,但是我不确定是否可以保证这种方法起作用:

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

Anyway, is there a way to determine the guaranteed minimum size of a bit-field member of a C struct in bits (or at least in bytes)? 无论如何,有没有一种方法可以确定以位(或至少以字节为单位)的C结构的位域成员的保证最小大小?

I am looking for an expression like sizeofbitfieldmemberinbits() that can be calculated by the compiler at build time (like ((mystruct){.threebits = -1}).threebits can be evaluated to 0x7 ). 我正在寻找一个像sizeofbitfieldmemberinbits()这样的表达式,它可以由编译器在构建时计算出来(例如((mystruct){.threebits = -1}).threebits可以评估为0x7 )。

Edit: As John Bollinger pointed out, the memory allocated for a bit-field member can be larger than the specified number of bits, but the member can never hold a value larger than (1 << #bits) - 1 . 编辑:正如John Bollinger指出的,分配给位字段成员的内存可以大于指定的位数,但是该成员永远不能保存大于(1 << #bits) - 1 However, when I attempt to set a value that is out of bounds, it will be truncated implicitly (at runtime). 但是,当我尝试设置一个超出范围的值时,它将被隐式截断(在运行时)。 With the assertion I want to check for cases where such truncation not just might occur, but when actually does . 通过断言,我想检查这种截断不仅可能发生,而且实际发生的情况

I am looking for an expression like sizeofbitfieldmemberinbits() that can be calculated by the compiler at build time 我正在寻找一个像sizeofbitfieldmemberinbits()这样的表达式,它可以在编译时由编译器计算出来

The Standard's term for what you are describing is " constant expression ": 该标准所描述的术语是“ 常量表达式 ”:

A constant expression can be evaluated during translation rather than runtime, and accordingly may be used in any place that a constant may be. 常量表达式可以在转换过程中而不是在运行时求值,因此可以在常量可能存在的任何位置使用它。

(C2011, 6.6/2) (C2011,6.6 / 2)

You go on to clarify the purpose for which you want to use such a constant expression: 您继续阐明使用此类常量表达式的目的:

With the assertion I want to check for cases where such truncation not just might occur, but when actually does . 通过断言,我想检查这种截断不仅可能发生,而且实际发生的情况

Note, however, that 但是请注意,

  1. For that purpose, the size of the bitfield is secondary. 为此,位域的大小是次要的。 What you actually want is the maximum representable value. 您真正想要的是最大可表示值。 For bitfields of signed types, maybe you want the minimum, too. 对于带符号类型的位域,也许您也想要最小值。

  2. You don't actually need a constant expression for use in a regular assertion such as you demonstrate (as opposed to a static assertion). 实际上,您不需要在演示等正则断言中使用常量表达式(与静态断言相对)。 The expression in a regular assertion is evaluated at runtime. 正则断言中的表达式在运行时求值。

  3. On the other hand, some expressions that do not satisfy the Standard's definition of a constant expression may still be computed at translation (compile) time by some implementations. 另一方面,某些实现仍可以在转换(编译)时计算不满足标准对常量表达式的定义的某些表达式。

Points (2) and (3) are fortunate for you, because bitfields have second-class types that are not directly expressible. 点(2)和(3)对您来说很幸运,因为位域具有无法直接表示的二等类型。 There are no values of any bitfield type outside the context of a host structure object, and there is no type name with which the effective type of a bitfield can be expressed. 在主机结构对象的上下文之外,没有任何位域类型的值,也没有类型名称可以用来表示位域的有效类型。 And that means there is no constant expression that evaluates to the number of bits or maximum value of a bitfield member, unless it incorporates prior knowledge of that member, because structs (including struct literals) are not among the operands that may appear in a suitable constant expression: 意味着没有常数表达式可以求位字段成员的位数或最大值,除非它结合了该成员的先验知识,因为结构(包括结构文字)不在合适的操作数中常数表达式:

An arithmetic constant expression shall have arithmetic type and shall only have operands that are integer constants, floating constants, enumeration constants, character constants, sizeof expressions whose results are integer constants, and _Alignof expressions. 算术常量表达式应具有算术类型,并且仅应具有整数常量,浮点常量,枚举常量,字符常量,结果为整数常量的sizeof表达式和_Alignof表达式的操作数。 Cast operators in an arithmetic constant expression shall only convert arithmetic types to arithmetic types, except as part of an operand to a sizeof or _Alignof operator. 算术常数表达式中的强制转换运算符只能将算术类型转换为算术类型,除非作为操作数的一部分转换为sizeof_Alignof运算符。

( C2011 6.6/8 ) C2011 6.6 / 8


After all that, I think the question really boils down to this: 毕竟,我认为问题实际上可以归结为:

I am not sure if this is guaranteed to work: 我不确定这是否可以正常工作:

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

For unsigned bitfields such as your mystruct.threebits , it's guaranteed to work in C99 or later. 对于mystruct.threebits之类的无符号位域,可以保证在C99或更高版本中工作。 Earlier versions of C do not have compound literals or designated initializers, however, and some C implementations you might run into even today do not conform to C99. 早期的C版本没有复合文字或指定的初始化程序,但是,甚至在今天您可能会遇到的某些C实现也不符合C99。 On such an implementation, you might instead just define a (maybe const , maybe static ) instance of your struct in which to record the limits ... 在这样的实现上,您可能只定义了一个结构实例(可能是const ,可能是static )以在其中记录限制...

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

... and then compare to its members: ...然后与它的成员进行比较:

assert(someveal <= mystruct_limits.threebits);

Note here that struct member initializers are subject to the same conversions that apply in simple assignment, so as long as the members have unsigned types, the -1s as initializer values are well defined to have the wanted effect. 请注意,在结构成员初始化器中进行的转换与在简单赋值中所应用的转换相同,因此,只要成员具有无符号类型,就很好地定义了作为初始化器值的-1s以产生所需的效果。

Note also that although the const is desirable for the purpose, it was not standardized until C99, either. 还请注意,尽管const对于此目的是理想的,但直到C99都没有对其进行标准化。 It was a pretty common extension before C99, though, and you are far less likely to run into a C compiler that rejects const than one that rejects compound literals. 但是,这是在C99之前相当普遍的扩展,与拒绝复合文字的C编译器相比,您遇到C编译器拒绝const可能性要小得多。

is there a way to determine the guaranteed minimum size of a bit-field member of a C struct in bits 有没有办法确定以位为单位的C结构的位字段成员的保证最小大小

I want to check for cases where such truncation not just might occur, but when actually does. 我想检查这种截断不仅可能发生,而且实际发生的情况。

assert() is insufficient as its related code is not certainly present at runtime. assert()不足,因为它的相关代码在运行时不一定存在。

Check against the maximum value of the field. 检查该字段的最大值。 Easy to do when the field is some unsigned type. 当字段是一些无符号类型时,很容易做到。

#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;
}

Output 输出量

Truncation will occur, 9
Truncation will occur, 8
Truncation will occur, 9
Truncation will occur, 8
Truncation will occur, 9

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM