如何获取结构体中的位数组?

发布于 2024-12-15 14:26:44 字数 1523 浏览 4 评论 0原文

我正在思考(因此正在寻找一种学习方法,而不是更好的解决方案)是否可以在结构中获取位数组。

让我通过一个例子来演示一下。想象这样一段代码:

#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("%u\n", a.bit0);
    printf("%u\n", a.bit1);
    printf("%u\n", a.bit2);
    printf("%u\n", 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("%u\n", b.bits[i]);
    return 0;
}

我尝试将 struct B 中的 bits 声明为 unsigned int bits[4]:1unsigned int bits:1[4] 或类似的东西无济于事。我最好的猜测是 typedef unsigned int bit:1; 并使用 bit 作为类型,但仍然不起作用。

我的问题是,这样的事情可能吗?如果是,怎么办?如果没有,为什么不呢? 1 位无符号 int 是有效类型,那么为什么不能获取它的数组呢?

再说一次,我不想替代它,我只是想知道这样的事情怎么可能。

PS 我将其标记为 C++,尽管代码是用 C 编写的,因为我假设该方法在两种语言中都存在。如果有一种 C++ 特定的方法来做到这一点(通过使用语言结构,而不是库),我也有兴趣知道。

更新:我完全知道我可以自己进行位运算。我过去已经做过一千次了。我对使用数组/向量并进行位操作的答案不感兴趣。我只是在想这个构造是否可能,而不是替代方案。

更新:对于不耐烦的人的回答(感谢neagoegab):

使用

typedef unsigned int bit:1;

我可以

typedef struct
{
    unsigned int value:1;
} bit;

使用#pragma pack正确

I was pondering (and therefore am looking for a way to learn this, and not a better solution) if it is possible to get an array of bits in a structure.

Let me demonstrate by an example. Imagine such a code:

#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("%u\n", a.bit0);
    printf("%u\n", a.bit1);
    printf("%u\n", a.bit2);
    printf("%u\n", a.bit3);
    return 0;
}

In this code, we have 4 individual bits packed in a struct. They can be accessed individually, leaving the job of bit manipulation to the compiler. What I was wondering is if such a thing is possible:

#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("%u\n", b.bits[i]);
    return 0;
}

I tried declaring bits in struct B as unsigned int bits[4]:1 or unsigned int bits:1[4] or similar things to no avail. My best guess was to typedef unsigned int bit:1; and use bit as the type, yet still doesn't work.

My question is, is such a thing possible? If yes, how? If not, why not? The 1 bit unsigned int is a valid type, so why shouldn't you be able to get an array of it?

Again, I don't want a replacement for this, I am just wondering how such a thing is possible.

P.S. I am tagging this as C++, although the code is written in C, because I assume the method would be existent in both languages. If there is a C++ specific way to do it (by using the language constructs, not the libraries) I would also be interested to know.

UPDATE: I am completely aware that I can do the bit operations myself. I have done it a thousand times in the past. I am NOT interested in an answer that says use an array/vector instead and do bit manipulation. I am only thinking if THIS CONSTRUCT is possible or not, NOT an alternative.

Update: Answer for the impatient (thanks to neagoegab):

Instead of

typedef unsigned int bit:1;

I could use

typedef struct
{
    unsigned int value:1;
} bit;

properly using #pragma pack

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

溺深海 2024-12-22 14:26:45

C++ 将使用 std::vectorstd::bitset

在 C 中,要模拟 std::vector 语义,您可以使用如下结构:

struct Bits {
    Word word[];
    size_t word_count;
};

其中 Word 是宽度与数据总线相等的实现定义类型CPU的;稍后使用的wordsize等于数据总线的宽度。

例如,对于 32 位机器,Worduint32_fast_t,对于 64 位机器是 uint64_fast_t
对于 32 位机器,wordsize 为 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 添加可调整大小功能,请创建一个调整大小函数,该函数在 Bits.word 上调用 realloc 并更改 Bits.word_count 相应地。其具体细节仍然是一个问题。

这同样适用于位索引的正确范围检查。

C++ would use std::vector<bool> or std::bitset<N>.

In C, to emulate std::vector<bool> semantics, you use a struct like this:

struct Bits {
    Word word[];
    size_t word_count;
};

where Word is an implementation-defined type equal in width to the data bus of the CPU; wordsize, as used later on, is equal to the width of the data bus.

E.g. Word is uint32_fast_t for 32-bit machines, uint64_fast_t for 64-bit machines;
wordsize is 32 for 32-bit machines, and 64 for 64-bit machines.

You use functions/macros to set/clear bits.

To extract a bit, use GET_BIT(bits, bit) (((bits)->)word[(bit)/wordsize] & (1 << ((bit) % wordsize))).

To set a bit, use SET_BIT(bits, bit) (((bits)->)word[(bit)/wordsize] |= (1 << ((bit) % wordsize))).

To clear a bit, use CLEAR_BIT(bits, bit) (((bits)->)word[(bit)/wordsize] &= ~(1 << ((bit) % wordsize))).

To flip a bit, use FLIP_BIT(bits, bit) (((bits)->)word[(bit)/wordsize] ^= (1 << ((bit) % wordsize))).

To add resizeability as per std::vector<bool>, make a resize function which calls realloc on Bits.word and changes Bits.word_count accordingly. The exact details of this is left as a problem.

The same applies for proper range-checking of bit indices.

左耳近心 2024-12-22 14:26:45

这是滥用的,并且依赖于扩展......但它对我有用:

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;
}

this is abusive, and relies on an extension... but it worked for me:

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;
}
烟柳画桥 2024-12-22 14:26:45

您还可以使用整数(整数或长整型)数组来构建任意大的位掩码。 select() 系统调用对其 fd_set 类型使用此方法;每个位对应于编号的文件描述符 (0..N)。宏定义为:FD_CLR清除一位,FD_SET设置一位,FD_ISSET测试一位,FD_SETSIZE为总位数。宏会自动找出要访问数组中的哪个整数以及该整数中的哪个位。在 Unix 上,请参阅“sys/select.h”;在Windows下,我认为它在“winsock.h”中。您可以使用 FD 技术来为位掩码进行自己的定义。在 C++ 中,我想您可以创建一个位掩码对象并重载 [] 运算符来访问各个位。

You can also use an array of integers (ints or longs) to build an arbitrarily large bit mask. The select() system call uses this approach for its fd_set type; each bit corresponds to the numbered file descriptor (0..N). Macros are defined: FD_CLR to clear a bit, FD_SET to set a bit, FD_ISSET to test a bit, and FD_SETSIZE is the total number of bits. The macros automatically figure out which integer in the array to access and which bit in the integer. On Unix, see "sys/select.h"; under Windows, I think it is in "winsock.h". You can use the FD technique to make your own definitions for a bit mask. In C++, I suppose you could create a bit-mask object and overload the [] operator to access individual bits.

一腔孤↑勇 2024-12-22 14:26:45

您可以使用结构指针创建位列表。不过,这将使用每位写入的多于一位的空间,因为它将使用每位一个字节(用于地址):

struct bitfield{
    unsigned int bit : 1;
};
struct bitfield *bitstream;

然后在此之后:

bitstream=malloc( sizeof(struct bitfield) * numberofbitswewant );

您可以像这样访问它们:

bitstream[bitpointer].bit=...

You can create a bit list by using a struct pointer. This will use more than a bit of space per bit written though, since it'll use one byte (for an address) per bit:

struct bitfield{
    unsigned int bit : 1;
};
struct bitfield *bitstream;

Then after this:

bitstream=malloc( sizeof(struct bitfield) * numberofbitswewant );

You can access them like so:

bitstream[bitpointer].bit=...
长伴 2024-12-22 14:26:44

不可能 - A像这样的构造不可能此处 - 不可能

人们可以尝试这样做,但结果将是一位存储在一个字节中

#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**

为了从一个字节访问各个位,这里有一个示例 (请注意,位域的布局取决于实现)

#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;
    }
}

NOT POSSIBLE - A construct like that IS NOT possible(here) - NOT POSSIBLE

One could try to do this, but the result will be that one bit is stored in one byte

#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;
}

output:

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**

In order to access individual bits from a byte here is an example (Please note that the layout of the bitfields is implementation dependent)

#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;
    }
}
疯到世界奔溃 2024-12-22 14:26:44

在 C++ 中,您使用 std::bitset<4>。这将使用最少数量的单词进行存储,并对您隐藏所有屏蔽。将 C++ 库与该语言分开确实很困难,因为该语言的大部分内容都是在标准库中实现的。在 C 中,没有直接的方法来创建像这样的单个位数组,而是创建一个四位元素或手动进行操作。

编辑:

1 位无符号 int 是有效类型,所以为什么你不能
获取它的数组?

实际上,除了创建结构/类成员的上下文之外,您不能在任何地方使用 1 位无符号类型。在这一点上,它与其他类型非常不同,它不会自动遵循您可以创建它们的数组。

In C++ you use std::bitset<4>. This will use a minimal number of words for storage and hide all the masking from you. It's really hard to separate the C++ library from the language because so much of the language is implemented in the standard library. In C there's no direct way to create an array of single bits like this, instead you'd create one element of four bits or do the manipulation manually.

EDIT:

The 1 bit unsigned int is a valid type, so why shouldn't you be able
to get an array of it?

Actually you can't use a 1 bit unsigned type anywhere other than the context of creating a struct/class member. At that point it's so different from other types it doesn't automatically follow that you could create an array of them.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文