其他分享
首页 > 其他分享> > 有符号数在计算机中的存储及在C语言中的运用

有符号数在计算机中的存储及在C语言中的运用

作者:互联网

前言:近期在调试一个博世的三轴加速度传感器时,在用c写有符号数相关的运算和操作相关的代码时,进一步去理解了有符号数的应用。


首先在阅读相关文档时,发现了对寄存器描述中出现Two's complement,实际是为了说明该寄存器读出的值是以补码的形式存储,假设有两个八位寄存器,第一个寄存器中有低四位(LSB)和第二个寄存器有高八位(MSB)组成了一个12位的数据,这12位数据以补码的形式读出,其中最高位表示的是符号,即在代码运算操作时要将该补码进行转换成源码操作
譬如:读出的数是0xFE0 -> 0b1111 1110 0000
这是一个负数,此时要将再取补操作,即取反加一
取反:0b0000 0001 1111 加一:0b0000 0010 0000 -> 32(十进制)
++取反操作编程时:直接~(0xFE0) 或 0xFFF - 0xFE0++

(1)、但需要注意的是取反~操作计算机是相对于8位/16位/32位为单位每一位取反的,譬如这里定义16位操作int16_t(0xFE0),那么每一位都按位取反int16_t(~0xFE0),得到0xF01F(0b‭111 1 0000 0001 1111‬ );这样相对于12位有符号数的操作是不对的;其次正确按照 0xFFF - 0xFE0这样取反操作,int16_t(0xFE0)这样相对于16位数的操作来说这是一个正数,但是对于12位寄存器(bit11表示负数),所以取反加一后再加一个“-”号(因为负数反码的最高位是不变的),当成一个十进制数在代码中操作,所以推荐使用“-(0xFFF-0xFE0 +1)”这样的写法

int16_t x;
x =( i2c_read_byte(0x02) &0xf0)>>4;
x=x|((i2c_read_byte(0x03)&0xff)<<4);//12bit
if(x>(0xfff/2))
{
x=-(0xfff-x);
}
x=(x*9.8)/(0xfff/2/2);//当量程为±2g时,转换为g/s的加速度换算公式

(2)如果正好是16位的寄存器,假设读出来的值是0x8FE0 -> 0b1000 1111 1110 0000,计算机取反时最高位是不变的
取反:0b0111 0000 0001 1111 (0xFFFF-0x8FE0)
加一:0b0111 0000 0010 0000
==注==:因为计算机取反(~)是每一位都取反,实际取反码最高位为1表示负数是不变的即最高位不动其他位取反,所以按照我们这样的操作最后在取反加一后,还要加“-”负号,相当于把“符号位被翻转成正后”的负号再找回来

有符号数计算存储测试:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
   int ch1 = 0x00000001;//0b1000 0001;  
   int ch2 = 0x80000002;//0b1000 0010;  
   //这里的0x80000002并不代表十进制-2;这里只是某一个负数所存储的补码,这个负数为
   //-2147483646
   int ch3 = ch1 + ch2;
   if(((ch2&0x80000000)>>31) > 0)
   {
   printf("ch1 = %d\n", ch1); //1
   printf("ch2 = %x\n", ~ch2);  //7ffffffd
   printf("ch1 + ch2 = %d\n", ch3); //-2147483645
   printf("ch1 + ch2 = %x\n", ch3); //80000003
   }

   return(0);
}

更多有关内容可参考阅读:
1.关于Two's complement
2.原码反码补码的相互转换
3.计算机中带符号的整数为何采用二进制的补码进行存储
4.计算机中的有符号数都是以二进制的补码形式存储的

标签:存储,0000,0xFE0,补码,取反,C语言,ch2,寄存器,数在
来源: https://www.cnblogs.com/muziyu/p/12346823.html