Как получить массив битов в структуре?
Я размышлял (и поэтому ищу способ узнать это,и не лучшее решение) если возможно получить массив битов в структуре.
позвольте мне продемонстрировать на примере. Представьте себе такой код:
#include <stdio.h>
struct A
{
unsigned int bit0:1;
unsigned int bit1:1;
unsigned int bit2:1;
unsigned int bit3:1;
};
int main()
{
struct A a = {1, 0, 1, 1};
printf("%un", a.bit0);
printf("%un", a.bit1);
printf("%un", a.bit2);
printf("%un", a.bit3);
return 0;
}
в этом коде у нас есть 4 отдельных бита, упакованных в структуру. К ним можно обращаться индивидуально, оставляя работу по обработке битов компилятору. Мне было интересно, есть ли такая вещь возможно:
#include <stdio.h>
typedef unsigned int bit:1;
struct B
{
bit bits[4];
};
int main()
{
struct B b = {{1, 0, 1, 1}};
for (i = 0; i < 4; ++i)
printf("%un", b.bits[i]);
return 0;
}
Я пытался объявить bits
на struct B
as unsigned int bits[4]:1
или unsigned int bits:1[4]
или подобные вещи бесполезно. Мое лучшее предположение было typedef unsigned int bit:1;
и использовать bit
как тип, но все еще не работает.
мой вопрос в том, возможно ли такое? Если да, то как? Если нет, то почему? 1 бит unsigned int является допустимым типом, так почему бы вам не получить его массив?
опять же, я не хочу замены для этого, мне просто интересно, как такое это возможно.
P. S. Я маркировка это как C++, хотя и код написан на C, потому что я предполагаю, что метод существует в обоих языках. Если есть конкретный способ сделать это (используя языковые конструкции, а не библиотеки), мне также было бы интересно узнать.
UPDATE: я полностью осознаю, что могу выполнять битовые операции самостоятельно. Я делал это тысячу раз в прошлом. Меня не интересует ответ, в котором говорится: вместо этого array / vector и выполните битовые манипуляции. Я только думаю, возможна ли эта конструкция или нет, а не альтернатива.
Update: ответ для нетерпеливых (благодаря neagoegab):
вместо
typedef unsigned int bit:1;
я мог бы использовать
typedef struct
{
unsigned int value:1;
} bit;
правильно используя #pragma pack
6 ответов
НЕ ВОЗМОЖНО - такая конструкция невозможно(здесь) - НЕ ВОЗМОЖНО
можно было бы попробовать сделать это, но результатом будет то, что один бит хранится в одном байте
#include <cstdint>
#include <iostream>
using namespace std;
#pragma pack(push, 1)
struct Bit
{
//one bit is stored in one BYTE
uint8_t a_:1;
};
#pragma pack(pop, 1)
typedef Bit bit;
struct B
{
bit bits[4];
};
int main()
{
struct B b = {{0, 0, 1, 1}};
for (int i = 0; i < 4; ++i)
cout << b.bits[i] <<endl;
cout<< sizeof(Bit) << endl;
cout<< sizeof(B) << endl;
return 0;
}
выход:
0 //bit[0] value
0 //bit[1] value
1 //bit[2] value
1 //bit[3] value
1 //sizeof(Bit), **one bit is stored in one byte!!!**
4 //sizeof(B), ** 4 bytes, each bit is stored in one BYTE**
для доступа к отдельным битам из байта вот пример (обратите внимание, что макет bitfields является реализацией зависимый)
#include <iostream>
#include <cstdint>
using namespace std;
#pragma pack(push, 1)
struct Byte
{
Byte(uint8_t value):
_value(value)
{
}
union
{
uint8_t _value;
struct {
uint8_t _bit0:1;
uint8_t _bit1:1;
uint8_t _bit2:1;
uint8_t _bit3:1;
uint8_t _bit4:1;
uint8_t _bit5:1;
uint8_t _bit6:1;
uint8_t _bit7:1;
};
};
};
#pragma pack(pop, 1)
int main()
{
Byte myByte(8);
cout << "Bit 0: " << (int)myByte._bit0 <<endl;
cout << "Bit 1: " << (int)myByte._bit1 <<endl;
cout << "Bit 2: " << (int)myByte._bit2 <<endl;
cout << "Bit 3: " << (int)myByte._bit3 <<endl;
cout << "Bit 4: " << (int)myByte._bit4 <<endl;
cout << "Bit 5: " << (int)myByte._bit5 <<endl;
cout << "Bit 6: " << (int)myByte._bit6 <<endl;
cout << "Bit 7: " << (int)myByte._bit7 <<endl;
if(myByte._bit3)
{
cout << "Bit 3 is on" << endl;
}
}
В C++ вы используете std::bitset<4>
. Это позволит использовать минимальное количество слов для хранения и скрыть от вас всю маскировку. Очень сложно отделить библиотеку C++ от языка, потому что большая часть языка реализована в стандартной библиотеке. В C нет прямого способа создать массив одиночных битов, как это, вместо этого вы бы создали один элемент из четырех битов или сделали манипуляцию вручную.
изменить:
1 бит unsigned int является допустимым типом, так почему же ты не можешь? чтобы получить массив?
фактически вы не можете использовать 1-битный тип без знака нигде, кроме контекста создания члена структуры / класса. В этот момент он настолько отличается от других типов, что автоматически не следует, что вы можете создать массив из них.
C++ будет использовать std::vector<bool>
или std::bitset<N>
.
в C, чтобы подражать std::vector<bool>
семантика, вы используете такую структуру:
struct Bits {
Word word[];
size_t word_count;
};
здесь Word
- это определенный реализацией тип, равный по ширине шине данных процессора;wordsize
, как используется позже, равно ширине шины данных.
Е. Г. Word
is uint32_fast_t
для 32-битных машин, uint64_fast_t
для 64-битных машин;
wordsize
32 для 32-разрядных машин и 64 для 64-разрядных машины.
вы используете функции/макросы для установки/сброса битов.
чтобы извлечь немного, используйте GET_BIT(bits, bit) (((bits)->)word[(bit)/wordsize] & (1 << ((bit) % wordsize)))
.
чтобы установить немного, используйте SET_BIT(bits, bit) (((bits)->)word[(bit)/wordsize] |= (1 << ((bit) % wordsize)))
.
чтобы очистить немного, используйте CLEAR_BIT(bits, bit) (((bits)->)word[(bit)/wordsize] &= ~(1 << ((bit) % wordsize)))
.
чтобы перевернуть немного, используйте FLIP_BIT(bits, bit) (((bits)->)word[(bit)/wordsize] ^= (1 << ((bit) % wordsize)))
.
добавить высоты состоянию на std::vector<bool>
, сделайте функцию изменения размера, которая вызывает realloc
on Bits.word
и изменения Bits.word_count
соответственно. Точные детали этого остаются проблемой.
то же применяется для правильной проверки диапазонов битовых индексов.
это оскорбительно и зависит от расширения... но это сработало для меня:
struct __attribute__ ((__packed__)) A
{
unsigned int bit0:1;
unsigned int bit1:1;
unsigned int bit2:1;
unsigned int bit3:1;
};
union U
{
struct A structVal;
int intVal;
};
int main()
{
struct A a = {1, 0, 1, 1};
union U u;
u.structVal = a;
for (int i =0 ; i<4; i++)
{
int mask = 1 << i;
printf("%d\n", (u.intVal & mask) >> i);
}
return 0;
}
вы также можете использовать массив целых чисел (ints или longs) для создания произвольно большой битовой маски. Системный вызов select () использует этот подход для своего типа fd_set; каждый бит соответствует нумерованному файловому дескриптору (0..Северный.) Макросы определены: FD_CLR для очистки бита, FD_SET для установки бита, FD_ISSET для тестирования бита, а FD_SETSIZE-общее количество битов. Макросы автоматически вычисляют, какое целое число в массиве для доступа и какой бит в целом. В Unix см. раздел " sys / select.ч"; под Windows, я думаю, это в " winsock.ч." Вы можете использовать метод FD, чтобы сделать свои собственные определения для битовой маски. В C++, я полагаю, вы можете создать объект битовой маски и перегрузить оператор [] для доступа к отдельным битам.
вы можете создать список битов с помощью указателя структуры. Это будет использовать больше, чем бит пространства на бит, хотя, поскольку он будет использовать один байт (для адреса) на бит:
struct bitfield{
unsigned int bit : 1;
};
struct bitfield *bitstream;
после этого:
bitstream=malloc( sizeof(struct bitfield) * numberofbitswewant );
вы можете получить к ним доступ, как так:
bitstream[bitpointer].bit=...