Ошибка при попытке определить 1024-битное (128-байтовое) битовое поле.

Я хотел бы определить большое битовое поле с целью быстрого мониторинга состояния очень большой структуры элементов. Вот что у меня есть до сих пор:

#define TOTAL_ELEMENTS 1021

typedef struct UINT1024_tag
{
   UINT8 byte[128];
} UINT1024;

typedef struct flags_tag
{
   UINT1024:TOTAL_ELEMENTS;
} flags_t;

Когда я пытаюсь скомпилировать это, я получаю сообщение об ошибке, "ошибка: битовое поле `‹anonymous›' имеет недопустимый тип"

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

Любые мысли или предложения будут оценены.


person Jim Fell    schedule 19.10.2009    source источник
comment
Рассмотрим просто использование массива логических значений.   -  person GManNickG    schedule 20.10.2009
comment
К сожалению, я застрял на C, поэтому расширения C++ мне не подходят.   -  person Jim Fell    schedule 20.10.2009
comment
Упс. Даже в этом случае будет недостаточно массива целых чисел?   -  person GManNickG    schedule 20.10.2009


Ответы (4)


Битовые поля должны умещаться в пределах одного целого числа, вы не можете использовать произвольные размеры. Честно говоря, реализация битового поля ANSI немного нарушена. Он также пропускает много других вещей, таких как управление отступами и макетом, которые обычно нужны реальным приложениям. Я бы подумал о написании некоторых макросов или функций доступа, чтобы абстрагироваться от больших размеров и отказаться от синтаксиса битового поля.

person Andy Ross    schedule 19.10.2009
comment
Спасибо, Энди. Примерно так я и предполагал. По сути, моя основная структура состоит из нескольких более мелких структур. Использование макросов — интересная идея; Я подумаю еще. - person Jim Fell; 20.10.2009
comment
В итоге я полагаюсь на библиотеку, которую я написал давным-давно, для обработки битовых полей; в частности, переменной длины. Очень удобно для сжатия переменной длины. Большинство людей, которых я знаю, которым нужны какие-либо серьезные манипуляции с битами, в конечном итоге создают свои собственные, потому что никто, кажется, не удосужился сделать приличную библиотеку. - person std''OrgnlDave; 25.04.2012

В стандартном языке C битовые поля могут быть определены только с ограниченным набором типов. В C89/90 эти типы ограничены int, signed int и unsigned int (малоизвестная деталь заключается в том, что в этом контексте int не гарантируется эквивалентностью signed int). В C99 к поддерживаемому набору был добавлен тип _Bool. Любые другие типы не могут использоваться в объявлении битового поля.

На практике, как популярное расширение, компиляторы обычно допускают любой целочисленный тип (или также тип перечисления) в объявлении битового поля. Но тип struct... Нет, я не знаю ни одного компилятора, который позволил бы это (не говоря уже о том, что это не имеет особого смысла).

person AnT    schedule 19.10.2009

использовать

 UINT128 blaha;

Вы не определяете битовое поле.

Я не уверен, что вы понимаете, что такое битовое поле. I битовое поле — это количество битов. Не массив структур или что-то подобное. Что именно вы ожидаете от своего кода?

Изменить: теперь понятно. Нет, вы не можете использовать свои собственные типы, только целые числа.

Попробуйте это (непроверенный код):

struct bit1024 {
  unsigned char byte[128];
};
struct bit1024 foo;
void
set(struct bit1024*lala, int n, int v)
{
  lala->byte[n/8] |= 1<<(n % 8);
  if (!v) {
    lala->byte[n/8] ^= 1<<(n % 8);
  }
}
int
get(struct bit1024*lala, int n)
{
  return 1 & (lala->byte[n/8] >> (n % 8));
}
person Thomas    schedule 19.10.2009
comment
Спасибо, но индексация в пространство памяти не проблема. Я просто искал чистый способ объявить это и заставить компилятор сделать часть работы за меня. - person Jim Fell; 20.10.2009

Как уже говорили другие, стандарт C не позволяет битовым полям превышать размер их присоединенного целочисленного типа.

Я бы предложил использовать простые массивы с некоторой магией макросов:

#include <limits.h>
#include <stdio.h>
#include <string.h>

// SIZE should be a constant expression
// this avoids VLAs and problems resulting from being evaluated twice
#define BITFIELD(SIZE, NAME) \
    unsigned char NAME[(SIZE) / CHAR_BIT + ((SIZE) % CHAR_BIT != 0)]

static inline void setbit(unsigned char field[], size_t idx)
{ field[idx / CHAR_BIT] |= 1u << (idx % CHAR_BIT); }

static inline void unsetbit(unsigned char field[], size_t idx)
{ field[idx / CHAR_BIT] &= ~(1u << (idx % CHAR_BIT)); }

static inline void togglebit(unsigned char field[], size_t idx)
{ field[idx / CHAR_BIT] ^= 1u << (idx % CHAR_BIT); }

static inline _Bool isbitset(unsigned char field[], size_t idx)
{ return field[idx / CHAR_BIT] & (1u << (idx % CHAR_BIT)); }

int main(void)
{
    BITFIELD(1025, foo);
    printf("sizeof foo = %u\n", sizeof foo);

    memset(foo, 0, sizeof foo);
    printf("%i", isbitset(foo, 1011));

    setbit(foo, 1011);
    printf("%i", isbitset(foo, 1011));

    unsetbit(foo, 1011);
    printf("%i", isbitset(foo, 1011));
}

Надеюсь, я не испортил бит-операции...

person Christoph    schedule 19.10.2009