【计组补码原码】【无符号数与有符号数的运算】有关由C无符号数与有符号数运算隐式强制转换有符号数为无符号数引起的(-1)与无符号数比较运算的‘反常’ 结果与无符号数与有符号数补码原码存储原理的介绍

目录

1. 问题与结论

1.1 问题:

1.2 结论为:

1.3 debug过程、c/c++如何查看变量类型、string.length()返回值类型

2.无符号数、有符号数负数及其补码、有符号数正数和0及其原码表示存储机制

3.问题解决:c/c++运算过程有符号数的隐式转换与其二进制存储位模式的不变性-,细看-1 < 25u强制转换和比较过程。

3.1上段引用强制转换情况的发生是隐式发生的,发生的条件即运算符包含最少一个无符号数

3.2 “这种方法对于标准的算数运算来说并无多大差异”这句话我现在还没弄明白,因为

3.3回归正题,-1 < 25u,细看其强制转换和比较过程


1. 问题与结论

1.1 问题:

为什么 -1 大于 25u 而 -1 小于 25。

1.2 结论为:

当无符号数和有符号数进行运算(不管关系运算像>和<;还是算数运算+-*/),C/c++都会隐式的将有符号类型转换为无符号类型,但底层存储形式(即位模式不改变),通俗的讲就是二进制的01顺序及其数量不改变,改变的是解释这些二进制的方式,用解释无符号数的规则去解释有符号数。

1.3 debug过程、c/c++如何查看变量类型、string.length()返回值类型

        遇到这个问题是因为学习kmp算法中有一步判断‘i<s.length()&&j<t.length()’很是奇怪当j==-1时,即-1<t.length()导致无法循环,后来我尝试对条件进行debug

fee50e393df04fe3aedded0745de1e1c.png

3ba8d2f2e9b44381bb1cfb9ee0510e13.png

 结果显而易见,-1<t.length() is false  (注意我这里仅仅用t.length()而不用直接的整数,其实如果你要输入整数只要在数后面加u,例如-1<25u,25u为无符号常量,具体可以去必应搜索)。可以运行以下查看结果,这就是这篇博客要记录解决的问题:为什么 -1 大于 25u 而 -1 小于 25

#include<iostream>
using namespace std;

int main()
{
	if(!(-1<25u))
		cout<<"-1 大于 25u"<<endl;
	if(-1<25)
		cout<<"-1 小于 25"<<endl;
 } 

输出:

-1 大于 25u
-1 小于 25

        另补充以下string.length()返回类型为无符号类型

        还有如何用函数求变量数据类型

#include<iostream>
#include <typeinfo> 
#include <cxxabi.h>
using namespace std;

int main()
{
	string str="123457878";
	//直接用 typeid(s.length()).name()只会输出数据类型缩写 
	//而下方语句输出全称 
	cout<<abi::__cxa_demangle(typeid(str.length()).name(),0,0,0 )<<endl;
 } 

输出:

unsigned long long

2.无符号数、有符号数负数及其补码、有符号数正数和0及其原码表示存储机制

(1)无论什么信息存储到计算机内就是二进制的01序列(当然包括数)

(2)接下来我们重点关注无符号(unsigned)整数即没有正负号的数和有符号整数即[-∞,+∞]内的整数。

(3)绝大部分机器对于c语言存储有符号负数均采用补码(two's s-complement)表示。从补码二进制转十进制角度理解(CSAPP中45页)补码:

设有a在内存中以2字节也就是8位二进制存储 short a;

(3-1)位模式表示

此时a二进制位模式为(左边为高位,右边为地位) [x7,x6,x5,x4,x3,x2,x1,x0]

(3-2)二进制补码转十进制

此时最高位x7权值为(-1*2^7)可以理解为符号位(当然这是另一种理解角度,别跟这里的最高位负权值理解矛盾);,其余权值都为(2^6,2^5......2^0)

即:{ -2^7,2^6,2^5,2^4,2^3,2^2,2^1,2^0 }

举个例子:当a =-1;

则其补码二进制表示为[ 1,1,1,1,1,1,1,1 ],我们根据权值计算其十进制: ∑(二进制位*权值)

1*(-1*2^7)+1*(2^6)+1*(2^5)+1*(2^4)+1*(2^3)+1*(2^2)+1*(2^1)+1*(2^0)= -1

(4)对于c语言存储有符号正数和0均采用原码存储表示,从原码二进制转十进制角度理解:

原码的最高位 (第八位,也就是x7) 必须是0,其它x0~x6位(还是假设8位)是否01都可以,转换成十进制的权值也即 { 2^6,2^5......2^0 }

举个例子:当 short a =17;

则其原码二进制表示为[ 0,0,0,1,0,0,0,1],我们根据权值计算其十进制: ∑(二进制位*权值)

0*(1*2^7)+0*(2^6)+0*(2^5)+1*(2^4)+0*(2^3)+0*(2^2)+0*(2^1)+1*(2^0)= 16+1=17

举个例子:当 short a =0;

则其原码二进制表示为[ 0,0,0,0,0,0,0,0 ]

(5)对于无符号数,没有正负号,也就是不需要最高位的符号位,也就是最高位权值没有负号且01任意,那么每个二进制都能发挥它每一位的价值(没错,说的就是最高位)无符号二进制转十进制:

我们接着用8位的 short a;

(4-1)位模式表示

此时a二进制位模式为(左边为高位,右边为地位) [x7,x6,x5,x4,x3,x2,x1,x0]

(3-2)二进制补码转十进制

此时每一位权值为{ 2^7,2^6,2^5,2^4,2^3,2^2,2^1,2^0 }

举个例子:当a = 44 ;

44=32+8+4=1*2^5+1*2^3+1*2^4=0*2^7+0*2^6+1*2^5+1*2^4+1*2^3+0*2^2+0*2^1+0*2^0

则其无符号数二进制表示为[ 0,0,1,1,1,0,0,0 ],

反过来,我们根据权值计算其十进制: ∑(二进制位*权值)

0*2^7+0*2^6+1*2^5+1*2^4+1*2^3+0*2^2+0*2^1+0*2^0=44

3.问题解决:c/c++运算过程有符号数的隐式转换与其二进制存储位模式的不变性-,细看-1 < 25u强制转换和比较过程。

        “由于C语言对同时包含有符号和无符号数表达式的这种处理方式,出现了一些奇特的行为,当执行一个运算时,如果它的一个运算数是有符号的而另一个是无符号的,那么C语言会隐式地将有符号数强制转换为无符号数,并假设这两个数是非负的,来执行这个运算......这种方法对于标准的算数运算来说并无多大差异,但对于<和> 这样的关系运算符来说,会导致不可思议的结果。”                                                                                                                  ————《CSAPP》53页

如下解释:

3.1上段引用强制转换情况的发生是隐式发生的,发生的条件即运算符包含最少一个无符号数

例如:1+2u;  -1+2u, -1<123u, 1u>23

3.2 这种方法对于标准的算数运算来说并无多大差异”这句话我现在还没弄明白,因为

#include<iostream>
#include <typeinfo> 
#include <cxxabi.h>
using namespace std;

int main()
{
	string str="1";
	cout<<abi::__cxa_demangle(typeid(-8+str.length()).name(),0,0,0 )<<endl;
	cout<<-8+str.length()<<endl;
	cout<<"---------------------------------"<<endl;
	cout<<abi::__cxa_demangle(typeid(-8+1u).name(),0,0,0 )<<endl;
	cout<<-8+1u<<endl;
	cout<<"---------------------------------"<<endl;
	cout<<abi::__cxa_demangle(typeid(-8+1).name(),0,0,0 )<<endl;
	cout<<-8+1<<endl;
 } 

输出:

unsigned long long
18446744073709551609
---------------------------------
unsigned int
4294967289
---------------------------------
int
-7

Amazing!这怎不是影响?...

3.3回归正题,-1 < 25u,细看其强制转换和比较过程

有符号整数 假设还是 8位的 short a = -1;;

无符号常量 25u也假设存储在8位二进制中。

-1的二进制补码表示(还记得计算机存储负数是以补码形式):

1111 1111

25u二进制表示(没有正负,每一位都对该值的正向增大有正向贡献):

25=16+8+1    二进制为 0001 1001

Step1:  计算-1 < 25u,此时C看到了无符号数25,那么准备将有符号的-1强制转换为无符号数

Step2:计算机内存中1111 1111与0001 1001改变吗?不改变。此时1111 1111被解释为有符号数。

Step3: 1111 1111二进制转无符号的十进制  :

        1*2^7+1*2^6+1*2^5+1*2^4+1*2^3+1*2^2+1*2^1+1*2^0=255

        那么此时-1经过强制转换,变成了255

        25u已经是无符号数,所以0001 1001就是25,25就是0001 1001。

Step4:计算 255<25 显而易见 255 < 25 is false,即  -1 < 25u is false,

Over!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值