目录
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 大于 25u 而 -1 小于 25。
当无符号数和有符号数进行运算(不管关系运算像>和<;还是算数运算+-*/),C/c++都会隐式的将有符号类型转换为无符号类型,但底层存储形式(即位模式不改变),通俗的讲就是二进制的01顺序及其数量不改变,改变的是解释这些二进制的方式,用解释无符号数的规则去解释有符号数。
遇到这个问题是因为学习kmp算法中有一步判断‘i 结果显而易见,-1 输出: -1 大于 25u 另补充以下string.length()返回类型为无符号类型 还有如何用函数求变量数据类型 输出: unsigned long long (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 “由于C语言对同时包含有符号和无符号数表达式的这种处理方式,出现了一些奇特的行为,当执行一个运算时,如果它的一个运算数是有符号的而另一个是无符号的,那么C语言会隐式地将有符号数强制转换为无符号数,并假设这两个数是非负的,来执行这个运算......这种方法对于标准的算数运算来说并无多大差异,但对于<和> 这样的关系运算符来说,会导致不可思议的结果。” ————《CSAPP》53页 如下解释: 例如:1+2u; -1+2u, -1<123u, 1u>23 输出: unsigned long long Amazing!这怎不是影响?... 有符号整数 假设还是 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!#include
-1 小于 25#include
2.无符号数、有符号数负数及其补码、有符号数正数和0及其原码表示存储机制
3.问题解决:c/c++运算过程有符号数的隐式转换与其二进制存储位模式的不变性-,细看-1 < 25u强制转换和比较过程。
3.1上段引用强制转换情况的发生是隐式发生的,发生的条件即运算符包含最少一个无符号数
3.2 “这种方法对于标准的算数运算来说并无多大差异”这句话我现在还没弄明白,因为
#include
18446744073709551609
---------------------------------
unsigned int
4294967289
---------------------------------
int
-73.3回归正题,-1 < 25u,细看其强制转换和比较过程