无符号数相减,在作为时间轴时十分常见,这里分析一下它的原理。
单片机内部运算数据都采用补码运算(包括传递数据,加减等),计算后根据参数类型来解读补码对应的源码。根据单片机位数,可以知道一次运算中单片机带入的位数,如32位单片机会以32位进行运算,再根据对应数据的类型进行强制转化,注意对于有符号数强制转化会继承符号位。
正数补码为原码,负数补码为反码+1。
CPU中只有加法器,都使用数据的补码进行加法运算,因此,a-b会被看做a+(-b),即a的补码加-b的补码。
另外以s8为例,1000 0000=-0=-128(可以理解为此处的符号位溢出到外面了即1000 0000无符号时为128,此时第九位为符号位为1。计算机内部会直接认为有符号数且符号位为1且后面皆为0的为最大的负值),0000 0000 = +0 = 0
其计算举例如下:
定义:
u8 a=1,b=0xff,c;
u16 d;
c= a-b;
d= a-b;
结果:
c = 2
d = 0xff02
过程:
a = 0000 0000 0000 0000 0000 0000 0000 0001
a(补码) = 0000 0000 0000 0000 0000 0000 0000 0001 [正数补码与原码相同]
b = 0000 0000 0000 0000 0000 0000 1111 1111
-b = 1000 0000 0000 0000 0000 0000 1111 1111
-b(反码) = 1111 1111 1111 1111 1111 1111 0000 0000 [负数反码除符号位全取反]
-b(补码) = 1111 1111 1111 1111 1111 1111 0000 0001 [负数补码为反码加1]
(a-b)(补码) = a(补码)+-b(补码) = 1111 1111 1111 1111 1111 1111 0000 0010 =0xffff ff02
(1)若保存在无符号数据中:
若保存在u8中,取补码低8位,无符号数原码等于补码,按无符号数解析就为 0x02=2
保存在u16中,同理就为0xff02 = 65282
(2)若保存在有符号数据中:
若其保存在s8中补码强制转化为8位,此时符号位在第9位丢失,CPU认为本数据为正数,原码 = 补码 0x02 = 02(数据出现异常)
若其保存在有符号数s16中补码为0xff02,强制转化为16位并继承符号位,转化为原码 = 0x80fe = -254