2009-02-11 2 views
3

Краткая версия: Как узнать размер (в битах) отдельного поля поля C++?Получение размера отдельного поля из поля структуры 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) 

Я хотел бы знать, как получить размер отдельного поля, скажем, тест :: Field4. Вышеприведенный пример для обычного элемента структуры не работает. Есть идеи? Или кто-то знает причину, почему он не может работать? Я довольно убежден, что sizeof не поможет, поскольку он возвращает только размер в байтах, но если кто-то знает иначе, я все уши.

Спасибо!

+0

Я думаю, что вас могут обмануть, но я бы хотел, чтобы вас доказали неправильно. –

+0

Я бы хотел воспользоваться этой возможностью, чтобы продолжить свой крестовый поход против битполей - просто не используйте их: http://stackoverflow.com/questions/289900/why-this-unions-size-is-2-with- bitfields/290855 # 290855 –

ответ

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 ... 
+0

Существует мало смысла в этом, почему бы вам не просто использовать другие предложения времени компиляции, которые уже упоминались? –

+0

Поскольку вы все равно должны знать поля, это бессмысленно делать во время выполнения ... –

+0

Другие предложения требуют изменения исходного кода битового поля, этого нет. –

1

Это невозможно

Ответ на комментарий: Поскольку тип является только INT, нет типа «немного». Синтаксис назначения битового поля - это просто короткая рука для выполнения побитового кода для чтения и записи.

+0

У вас есть документация, указывающая на меня? Или, по крайней мере, ваши рассуждения? Мне просто интересно. –

1

Я не думаю, что вы можете это сделать. Если вы действительно нужен размер, я предлагаю вам использовать #define (или, еще лучше, если возможно const переменных - Я не уверен, если это законно), а так:

#define TEST_FIELD1_SIZE 4 
struct Test { 
    unsigned field1 : TEST_FIELD1_SIZE; 
    ... 
} 
+0

const является законным, если он является интегральным типом (в конце концов, он не может зарезервировать половину бит). Это лучшее, что я могу сделать. Благодарю. –

5

Вы можете не принимать sizeof бит и получить количество бит.

Лучше всего будет использовать #define с или 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 

Ради последовательности, я полагаю, вы можете переместить normal_member доверху и добавить запись в Sizes с помощью sizeof(normal_member). Однако это беспорядок с порядком ваших данных.

2

Использование ChrisW's idea (хороший, кстати), вы можете создать вспомогательный макрос:

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

+0

О наличии «чистого метода» и с учетом наличия: http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/has-xxx-template-def.html it можно сгенерировать (через макрос) шаблон с именем поля. Преимущество может заключаться в том, что вычисление должно происходить во время компиляции: поэтому можно написать «нормальное» рекурсивное определение log2 (после известной факториальной функции времени компиляции) и оптимизировать его. – Blaisorblade

Смежные вопросы