5

简短的版本是:如何学习 c++ 字段的单个字段的大小(以位为单位)?

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

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.

要获得整个 Test 对象的大小很容易,我们只是说

sizeof(Test); // returns 8, for 8 bytes total size

我们可以通过

sizeof(((Test*)0)->normal_member); // returns 4 (on my system)

我想知道如何获取单个字段的大小,例如 Test::field4。上面的普通结构成员示例不起作用。有任何想法吗?或者有人知道它不能工作的原因吗?我相当确信 sizeof 不会有帮助,因为它只返回以字节为单位的大小,但如果有人知道否则我会全神贯注。

谢谢!

4

6 回答 6

10

您可以在运行时计算大小,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 ...
于 2009-02-11T23:16:34.077 回答
5

您不能获取sizeof一个位域并获取位数。

您最好的选择是使用#defines 或enums:

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

为了保持一致性,我相信你可以移到normal_member顶部并在Sizesusing中添加一个条目sizeof(normal_member)。但是,这会扰乱您的数据顺序。

于 2009-02-11T23:08:40.397 回答
3

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

http://en.wikipedia.org/wiki/Sizeof

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

http://www-graphics.stanford.edu/~seander/bithacks.html

于 2009-02-11T23:10:48.020 回答
3

使用ChrisW 的想法(很好,顺便说一句),您可以创建一个辅助宏:

#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))。

于 2009-02-12T00:54:12.360 回答
1

这是不可能的

对评论的回答:因为类型只是一个 int,所以没有“位”类型。位域分配语法只是执行按位代码进行读写的简写。

于 2009-02-11T23:06:08.030 回答
1

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

#define TEST_FIELD1_SIZE 4
struct Test {
    unsigned field1 : TEST_FIELD1_SIZE;
    ...
}
于 2009-02-11T23:07:14.783 回答