Как получить массив битов в структуре?

Я размышлял (и поэтому ищу способ узнать это,и не лучшее решение) если возможно получить массив битов в структуре.

позвольте мне продемонстрировать на примере. Представьте себе такой код:

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