C语言 为什么无符号的3位位域会将-7绕到1

cbeh67ev  于 2023-08-03  发布在  其他
关注(0)|答案(2)|浏览(106)
#include <stdio.h>

struct test{
   unsigned int a:3;
};

int main (int argc, char *argv[])
{
  struct test b;
  b.a = -7; // implicit truncation to 1
  return 0;
}

字符串
-7是表示为1111的四位数。现在我的位字段只需要3位,并且有无符号限定符。据我所知,无符号3位整数的范围是0-7。根据这个假设,我首先尝试了-7 = 1111 = 15。这是一个关于+7的问题。我甚至考虑了MSB由于某种原因被忽略的可能性,但仍然没有答案。我能得到这个答案的唯一方法是当我取1111的2的补码时,它等于+1(编译器也是这么说的)。但我不知道为什么会这样。

li9yvcax

li9yvcax1#

以下是C11标准的内容,6.3.1.3 Signed and unsigned integers paragraph 3:
否则,如果新类型是无符号的,则通过重复地比新类型中可以表示的最大值多加或减一来转换该值,直到该值在新类型的范围内。60)
a为7,因此7+1=8的值被添加或减去,直到它在范围内。-7+8=1 => 1被存储。
-7在2补码中是(~7)+1,它是(~0b111)+0b1 = 0b11111000+0b1 = 0b111111001将其存储在3位中,您将获得最后3位:0b001=1
0b1111在4位有符号数中作为2的补码将是-1。对它应用2补数:(~1)+1 = (~0b1)+0b1 = 0b1110+0b1 = 0b1111 = -1
你是正确的,0b1111在一个4位有符号的数字作为有符号的幅度将是7,但没有人使用有符号的幅度了,AFAIK它被从C23中删除,只有2互补将被允许。即使在有符号的星等系统上,结果仍然是1,因为C标准要求它(如上面提到的段落)

e0bqpujr

e0bqpujr2#

  • 免责声明:这个答案只解释了为什么你的系统会像你观察到的那样运行。它并不声称对所有系统都是正确的。该标准不要求对位字段进行特定的实现,在其他系统上,结果可能完全不同。

一个3位宽的无符号整数只能取这8个不同的值:
| 二进制| binary |
| --| ------------ |
| 千| 000 |
| 001| 001 |
| 010| 010 |
| 011| 011 |
| 一百| 100 |
| 一百零一| 101 |
| 一百一十| 110 |
| 一百一十一| 111 |
现在你把-7赋值给这样一个整数。由于所有整数表达式(除了更宽的类型)都隐式计算为int,最有可能是2的补码,并且在您的机器上具有32位宽度,因此二进制值为0 b11111111111111111111111111001。
由于编译器通过截断目标类型的宽度来实现赋值,因此只存储最低的3位:0 b 001。这是十进制的1。

相关问题