从c++;结构域 简短的版本是:如何学习C++字段的单个字段的大小(以位为单位)?< /P>

从c++;结构域 简短的版本是:如何学习C++字段的单个字段的大小(以位为单位)?< /P>,c++,struct,field,sizeof,C++,Struct,Field,Sizeof,为了澄清,我正在谈论的领域的一个例子是: struct Test { unsigned field1 : 4; // takes up 4 bits unsigned field2 : 8; // 8 bits unsigned field3 : 1; // 1 bit unsigned field4 : 3; // 3 bits unsigned field5 : 16; // 16 more to make it a 32 bit struct

为了澄清,我正在谈论的领域的一个例子是:

struct Test {
    unsigned field1 : 4;  // takes up 4 bits
    unsigned field2 : 8;  // 8 bits
    unsigned field3 : 1;  // 1 bit
    unsigned field4 : 3;  // 3 bits
    unsigned field5 : 16; // 16 more to make it a 32 bit struct

    int normal_member; // normal struct variable member, 4 bytes on my system
};

Test t;
t.field1 = 1;
t.field2 = 5;
// etc.
要得到整个测试对象的大小很容易,我们只是说

sizeof(Test); // returns 8, for 8 bytes total size
我们可以通过

sizeof(((Test*)0)->normal_member); // returns 4 (on my system)
我想知道如何获得单个字段的大小,比如Test::field4。上面的普通结构成员示例不起作用。有什么想法吗?或者有人知道它不能工作的原因吗?我确信sizeof不会有帮助,因为它只返回字节大小,但如果有人知道其他情况,我洗耳恭听

谢谢

这是不可能的

对评论的答复:
因为类型只是一个int,所以没有“bit”类型。位字段赋值语法只是执行读写位代码的简写。

我认为你做不到。如果您真的需要大小,我建议您使用
#define
(或者,更好的是,如果可能,使用
const
变量——我不确定这是否合法),如下所示:


不能将
sizeof
作为一个位字段来获取位数

您最好使用
#define
s或
enum
s:

struct Test {
    enum Sizes {
        sizeof_field1 = 4,
        sizeof_field2 = 8,
        sizeof_field3 = 1,
        sizeof_field4 = 3,
        sizeof_field5 = 16,
    };

    unsigned field1 : sizeof_field1;  // takes up 4 bits
    unsigned field2 : sizeof_field2;  // 8 bits
    unsigned field3 : sizeof_field3;  // 1 bit
    unsigned field4 : sizeof_field4;  // 3 bits
    unsigned field5 : sizeof_field5;  // 16 more to make it a 32 bit struct

    int normal_member; // normal struct variable member, 4 bytes on my system
};

printf("%d\n", Test::sizeof_field1); // prints 4

为了保持一致性,我相信您可以使用
sizeof(normal\u member)
normal\u member
移动到顶部,并在
size
中添加一个条目。不过,这会打乱数据的顺序。

似乎不太可能,因为sizeof()以字节为单位,而您需要位

基于位计数答案,您可以使用


您可以计算运行时的大小fwiw,例如:

//instantiate
Test t;
//fill all bits in the field
t.field1 = ~0;
//extract to unsigned integer
unsigned int i = t.field1;
... TODO use contents of i to calculate the bit-width of the field ...
使用(顺便说一句,很好),您可以创建一个帮助器宏:

#define SIZEOF_BITFIELD(class,member,out) { \
    class tmp_;                             \
    tmp_.member = ~0;                       \
    unsigned int tmp2_ = tmp_.member;       \
    ++tmp2_;                                \
    out = log2(tmp2_);                      \
}

unsigned int log2(unsigned int x) {
    // Overflow occured.
    if(!x) {
        return sizeof(unsigned int) * CHAR_BIT;
    }

    // Some bit twiddling...  Exploiting the fact that floats use base 2 and store the exponent.  Assumes 32-bit IEEE.
    float f = (float)x;
    return (*(unsigned int *)&f >> 23) - 0x7f;
}
用法:

size_t size;
SIZEOF_BITFIELD(Test, field1, size);  // Class of the field, field itself, output variable.

printf("%d\n", size);  // Prints 4.

我尝试使用模板函数失败。但是,我不是模板方面的专家,因此可能仍然有一个干净的方法(例如,
sizeof_bitfield(Test::field1)
)。

我认为您可能会感到困惑,但我想被证明是错的。我想借此机会继续我对比特域的斗争——只是不要使用它们:你有一些文档可以告诉我吗?或者至少是你的推理?我只是好奇这一点。const是合法的,只要它是整数类型(毕竟不能保留半个位)。这也是我能做的最好的了。谢谢。这样做没有什么意义,为什么不使用前面提到的其他编译时建议呢?其他建议需要更改位字段的源代码,但事实并非如此。你的想法很好,ChrisW。我已经给出了一个如何使用这个的例子,参考了你的答案。关于拥有一个“干净的方法”,并且假设存在:可以(通过宏)生成一个给定字段名的模板。优点可能是计算必须在编译时进行:因此可以编写log2的“普通”递归定义(遵循著名的编译时阶乘函数)并对其进行优化。
size_t size;
SIZEOF_BITFIELD(Test, field1, size);  // Class of the field, field itself, output variable.

printf("%d\n", size);  // Prints 4.