C 联合位域转换



我不明白转换位域时会发生什么。

假设我们有这个联合和一个例子:

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) = %lun", sizeof(x));
  printf("x.data = %dn", x.data);
  printf("x.d = %dn", x.d);
  printf("x.m = %dn", x.m);
  printf("(unsigned char)x.d = %dn", (unsigned char)x.d);
  printf("(signed char)x.d = %dn", (signed char)x.d);
  printf("(signed char)x.m = %dn", (signed char)x.m);
  printf("(unsigned char)x.m = %dn", (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.datax.dx.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 给了我预期的结果,但为什么例如(无符号字符)x.d 返回 254?为什么它不返回 182,因为 x.data 和 x.d 位于相同的内存位置,我将 x.d 转换为与 x.data 类型相同的无符号字符。

x.dx.m没有通过强制转换显示任何变化,这是意料之中的。 x.d在这两种情况下都具有相同的位模式,但在被视为有符号时被解释为 -2,当这些相同的位被解释为无符号时,被解释为 254。

如果在联合中读取和写入一个变量,

则这些变量分组在一个联合中将节省空间,但是当您编写一个变量并读取另一个变量时,这是未定义的行为。

通过一个成员设置union并读回另一个union成员的行为在 C 中是未定义的

因此,试图分析这种特定情况下的行为是没有意义的。

您应该使用基于memcpy的解决方案进行重建:至少这样输出是可分析的。

另外,请注意,%zusizeof 值的适当格式说明符:目前,由于您使用%luprintf行为也未定义。

最新更新