编辑:我必须专门为此目的使用 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
在 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 个字节。
使用位字段不是一个好方法,因为联合内的分配顺序没有指定。此外,您不能制作位域数组,并且您的替代解决方案中的结构数组不是位数组,甚至没有定义大小,因为每个结构的填充可能大于 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
你不需要任何联合和位域:
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");
}
}