C 联合位域铸造
C union bitfields casting
我不明白转换位域时会发生什么。
假设我们有这个联合和一个例子:
union {
unsigned char data;
int d : 3;
unsigned char m : 3;
}x;
int main() {
x.data = 182;
// 182 (binary) -> 1 0 1 1 0 1 1 0
printf("sizeof(x) = %lu\n", sizeof(x));
printf("x.data = %d\n", x.data);
printf("x.d = %d\n", x.d);
printf("x.m = %d\n", x.m);
printf("(unsigned char)x.d = %d\n", (unsigned char)x.d);
printf("(signed char)x.d = %d\n", (signed char)x.d);
printf("(signed char)x.m = %d\n", (signed char)x.m);
printf("(unsigned char)x.m = %d\n", (unsigned char)x.m);
return 0;
}
这是输出:
/*
sizeof(x) = 4
x.data = 182
x.d = -2
x.m = 6
(unsigned char)x.d = 254 //?
(signed char)x.d = -2 //?
(signed char)x.m = 6 //?
(unsigned char)x.m = 6 //?
*/
现在,我理解 x.data
、x.d
和 x.m
输出,但我不理解的是我们在转换时得到的结果。
铸造时内存中发生了什么?为什么我们会得到这些结果:
(unsigned char)x.d
= 254
(signed char)x.d
= -2
(signed char)x.m
= 6
(unsigned char)x.m
= 6
编辑:
我不明白的是这是如何在内存中处理的,以及在铸造时读取了哪些部分。我将 182 放入 x.data 中,二进制为 10110110。x.data、x.m 和 x.d 给我预期的结果,但为什么例如 (unsigned char)x.d return 254?为什么 return 182 不是因为 x.data 和 x.d 位于相同的内存位置并且我将 x.d 转换为与 [=41= 相同类型的无符号字符] 是。
通过一个成员设置 union
并读回另一个 union
成员的行为在 C 中是 undefined
因此,尝试分析这种特定情况下的行为毫无意义。
您应该使用基于 memcpy
的解决方案进行重建:至少这样输出将是可分析的。
此外,请注意 %zu
是 sizeof
值的适当格式说明符:由于您使用 %lu
,目前 printf
行为也未定义。
x.d
和 x.m
显示没有因转换而发生变化,这是可以预料的。 x.d
在这两种情况下都具有相同的位模式,但当它被认为有符号时被解释为 -2,而当这些相同的位被解释为无符号时被解释为 254。
如果您在联合中读取和写入一个变量,那么将这些变量分组在一个联合中这一事实将节省 space,但当您写入一个变量并读取另一个变量时,这是未定义的行为。
我不明白转换位域时会发生什么。
假设我们有这个联合和一个例子:
union {
unsigned char data;
int d : 3;
unsigned char m : 3;
}x;
int main() {
x.data = 182;
// 182 (binary) -> 1 0 1 1 0 1 1 0
printf("sizeof(x) = %lu\n", sizeof(x));
printf("x.data = %d\n", x.data);
printf("x.d = %d\n", x.d);
printf("x.m = %d\n", x.m);
printf("(unsigned char)x.d = %d\n", (unsigned char)x.d);
printf("(signed char)x.d = %d\n", (signed char)x.d);
printf("(signed char)x.m = %d\n", (signed char)x.m);
printf("(unsigned char)x.m = %d\n", (unsigned char)x.m);
return 0;
}
这是输出:
/*
sizeof(x) = 4
x.data = 182
x.d = -2
x.m = 6
(unsigned char)x.d = 254 //?
(signed char)x.d = -2 //?
(signed char)x.m = 6 //?
(unsigned char)x.m = 6 //?
*/
现在,我理解 x.data
、x.d
和 x.m
输出,但我不理解的是我们在转换时得到的结果。
铸造时内存中发生了什么?为什么我们会得到这些结果:
(unsigned char)x.d
= 254(signed char)x.d
= -2(signed char)x.m
= 6(unsigned char)x.m
= 6
编辑: 我不明白的是这是如何在内存中处理的,以及在铸造时读取了哪些部分。我将 182 放入 x.data 中,二进制为 10110110。x.data、x.m 和 x.d 给我预期的结果,但为什么例如 (unsigned char)x.d return 254?为什么 return 182 不是因为 x.data 和 x.d 位于相同的内存位置并且我将 x.d 转换为与 [=41= 相同类型的无符号字符] 是。
通过一个成员设置 union
并读回另一个 union
成员的行为在 C 中是 undefined
因此,尝试分析这种特定情况下的行为毫无意义。
您应该使用基于 memcpy
的解决方案进行重建:至少这样输出将是可分析的。
此外,请注意 %zu
是 sizeof
值的适当格式说明符:由于您使用 %lu
,目前 printf
行为也未定义。
x.d
和 x.m
显示没有因转换而发生变化,这是可以预料的。 x.d
在这两种情况下都具有相同的位模式,但当它被认为有符号时被解释为 -2,而当这些相同的位被解释为无符号时被解释为 254。
如果您在联合中读取和写入一个变量,那么将这些变量分组在一个联合中这一事实将节省 space,但当您写入一个变量并读取另一个变量时,这是未定义的行为。