为什么我不能用位域创建一个结构数组?

问题描述 投票:0回答:3

编辑:我必须专门为此目的使用 union,因为本章是关于它们的。我所说的第一个任务的片段是基于:

设计一个名为byte_set的union,可以将多个int类型打散,使其所有组成字节都显示出来。 union的大小必须等于int类型的大小,而byte_set union的字段数不能超过两个

在 byte_set.h 文件中包含联合声明。

通过显示其连续字节的值来测试其对值为 0x41424344 的 int 数字的操作。

我目前正在学习 C99 中的联合

我的任务是这样的:

用户读取一个int,然后显示为:

  • 2x 字
  • 4x 字节
  • 4x 8 位(从最高有效位到最低有效位的 4 个八位字节)

具有以下限制:

  • 不使用按位运算符,
  • 不使用
    []
    运算符读取数组,
  • 只使用一个
    if
    (禁止三元运算)。

我的解决方案通过了测试,但我想问一下是否有任何方法可以使它在显示位值时更紧凑。

我的解决方案是这样的:

#include <stdio.h>

struct byte{
    unsigned char bit0:1;
    unsigned char bit1:1;
    unsigned char bit2:1;
    unsigned char bit3:1;
    unsigned char bit4:1;
    unsigned char bit5:1;
    unsigned char bit6:1;
    unsigned char bit7:1;
};

union bit_set{
    unsigned int number;
    unsigned short word[2];
    unsigned char byte[4];
    struct byte bytes[4];
};

int main() {
    union bit_set bit_set = {0};
    setvbuf(stdout, NULL, _IONBF, 0);
    printf("Podaj liczbę: ");
    if(!scanf("%u", &bit_set.number)){
        printf("Incorrect input");
        return 1;
    }
    printf("%u\n", bit_set.number);
    printf("%d %d\n", *bit_set.word, *(bit_set.word+1));
    printf("%d %d %d %d\n", *bit_set.byte, *(bit_set.byte+1), *(bit_set.byte+2), *(bit_set.byte+3));
    for(int i = 0; i < 4; i++){
        printf("%d", (bit_set.bytes+i)->bit7);
        printf("%d", (bit_set.bytes+i)->bit6);
        printf("%d", (bit_set.bytes+i)->bit5);
        printf("%d", (bit_set.bytes+i)->bit4);
        printf("%d", (bit_set.bytes+i)->bit3);
        printf("%d", (bit_set.bytes+i)->bit2);
        printf("%d", (bit_set.bytes+i)->bit1);
        printf("%d", (bit_set.bytes+i)->bit0);
        printf(" ");
    }

    return 0;
}

我的猜测是让它更紧凑:

struct byte{
    unsigned char bit0:1;
};

union bit_set{
    unsigned int number;
    unsigned short word[2];
    unsigned char byte[4];
    struct byte bits[32];
};

// ...

   for(int i = 0; i < 4; i++){
        for (int j = 7; j > 0; j--) {
            printf("%d", (bit_set.bits+j)->bit0);
        }
        printf(" ");
    }

上面的“紧凑”代码不会产生任何好的结果。对于输入:

Enter a number: 1

它产生:

1
1 0
1 0 0 0
0000000 0000000 0000000 0000000

例二:

Enter a number: 2

它产生:

2
2 0
2 0 0 0
0000000 0000000 0000000 0000000
arrays c c99 unions bit-fields
3个回答
4
投票

在 C 中,

struct
对象的最小大小为 1 个字节。

因此,在代码中

struct byte{
    unsigned char bit0:1;
};

union bit_set{
    unsigned int number;
    unsigned short word[2];
    unsigned char byte[4];
    struct byte bits[32];
};

成员

bits
struct byte
的32个元素的数组,其中每个元素的大小为1个字节。因此,该数组的总大小为 32 字节。您似乎期望数组的大小为 32 位,即 4 个字节。


0
投票

使用位字段不是一个好方法,因为联合内的分配顺序没有指定。此外,您不能制作位域数组,并且您的替代解决方案中的结构数组不是位数组,甚至没有定义大小,因为每个结构的填充可能大于 7 位。

使用

*(bit_set.byte+1)
来避免
[]
数组语法很好。或者,您可以使用指针并递增它。

这是一个修改版本,完全可移植到异国情调的架构:

int main(void) {
    union bit_set bit_set = { 0 };
    unsigned short *pw;
    unsigned char *pb;
    size_t i, n;

    printf("Enter a number: ");
    if (scanf("%d", &bit_set.number) != 1) {
        fprintf(stderr, "cannot read number\n");
        return 1;
    }
    //printf("%u\n", bit_set.number); // not in the task

    pw = bit_set.word;
    for (i = 0, n = countof(bit_set.word); i < n; i++) {
        unsigned word = *pw++;
        printf("0x%04x%c", word, " \n"[i == n - 1]);
    }
    pb = bit_set.byte;
    for (i = 0, n = countof(bit_set.byte); i < n; i++) {
        unsigned byte = *pb++;
        printf("0x%02x%c", byte, " \n"[i == n - 1]);
    }
    pb = bit_set.byte;
    for (i = 0, n = countof(bit_set.byte); i < n; i++) {
        unsigned byte = *pb++;
        for (unsigned k = UCHAR_MAX / 2 + 1; k != 0; k /= 2) {
            printf("%u", byte / k % 2);
        }
        printf("%c", " \n"[i == n - 1]);
    }
    return 0;
}

输出:

Enter a number: 1234
0x04d2 0x0000
0xd2 0x04 0x00 0x00
11010010 00000100 00000000 00000000

-1
投票

你不需要任何联合和位域:

void print(unsigned int x)
{
    unsigned int y = x;
    printf("0x%08X\n", x);
    printf("0x%04X 0x%04X\n", (x % (USHRT_MAX + 1)), (x / (USHRT_MAX + 1)));
    for(size_t i = 0; i < sizeof(x); i++)
    {
        printf("0x%02X ", x % (UCHAR_MAX + 1));
        x /= (UCHAR_MAX + 1);
    }
    printf("\n");
    for(size_t i = 0; i < sizeof(x) * CHAR_BIT; i++)
    {
        printf("%x%s", y % 2, (i + 1) % CHAR_BIT ? "" : " ");
        y /= 2;
    }
}



int main(void)
{
    srand(time(NULL));
    for(int x = 0; x < 10; x++)
    {
        print(rand());
        printf("\n-----------------------\n");
    }
}

https://godbolt.org/z/v3jW1bofs

© www.soinside.com 2019 - 2024. All rights reserved.