C中的位域数组

9

在C语言中,我有一个包含8个位的标志,并且我想使用位域一位一位地访问它,就像这样:

#include <stdio.h>
#include <stdint.h>

int main(void) {
    struct flags{
        uint8_t bits1:1;
        uint8_t bits2:1;
        uint8_t bits3:1;
        uint8_t bits4:1;
        uint8_t bits5:1;
        uint8_t bits6:1;
        uint8_t bits7:1;
        uint8_t bits8:1;
    };
    struct flags *my_flags;
    uint8_t x=6,i;

    my_flags=(struct flags *)&x;
    printf("%u\t",my_flags->bits5);
    printf("%u\t",my_flags->bits6);
    printf("%u\t",my_flags->bits7);
    printf("%u\t",my_flags->bits8);
    printf("%u\t",my_flags->bits1);
    printf("%u\t",my_flags->bits2);
    printf("%u\t",my_flags->bits3);
    printf("%u\t",my_flags->bits4);
    return 0;
}

当我运行程序时,我得到了预期的输出:0 0 0 0 0 1 1 0

但这需要编写太多的代码。

  1. 是否有类似于位域数组或其他解决方法?(或)
  2. C语言中是否有类似于my_flags->bits_i的东西,其中i将是循环中的计数器?

我知道C本身没有以上两种方法。但是有没有达到相同效果的替代方法呢?

2个回答

15
您可以使用带有匿名内部结构的联合体(C11):
union flags
{
    unsigned char u;
    struct
    {
        uint8_t bits1:1;
        uint8_t bits2:1;
        uint8_t bits3:1;
        uint8_t bits4:1;
        uint8_t bits5:1;
        uint8_t bits6:1;
        uint8_t bits7:1;
        uint8_t bits8:1;
    };
};

你可以这样使用:
union flags x = {0x42};

for (i = CHAR_BIT - 1; i >= 0; i--)
{
    printf("%d\t", (x.u >> i) & 1);
}

printf("\n");

并且要访问特定位:

x.bits8 = 1;
printf("%d\n", x.bits8);

匿名内部结构也是C89和C99的GNU扩展。


我以前从未像这样使用过联合。您能否解释一下这里发生了什么,以便更好地理解? - RatDon
3
这是一个由两个成员组成的联合:unsigned char 和匿名结构体。 结构体是匿名的,这使得您可以直接从联合对象访问其成员,例如在我的回答中使用的 x.bits8。请注意,翻译保持了原意并且尽可能地通俗易懂。 - ouah
如果 CHAR_BIT 是 16,那么怎么办?如果你正在使用 uint8_t,那么最好使用 8 而不是 CHAR_BIT - barak manos
1
@barakmanos OP正在使用uint8_t,这确实意味着它的系统具有CHAR_BIT8,因此我没有考虑使用CHAR_BIT16的这种奇特系统的地址。现在使用CHAR_BIT而不是神奇数字8更清楚地表示了意图。 - ouah

6
  1. No. You can't create an array of bit-field
  2. You can extract each bit by using >> and &

    int main() {
        int i, x=45;
        for(i=0; i<8; i++) {
            printf("%d", (x>>(7-i))&1);
        }
    }
    

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接