单位,补码之类的可以看这个:
http://www.cnblogs.com/dotnetcrazy/p/8178175.html
先说说大小端对齐的事情,然后再看:
内存最小单位==》Byte,int 占 4Byte
重点来了,大于Byte的数据类型在内存中存放需要有先后顺序(一个里面放不下,那么在内存中就要有先后顺序了)
小端对齐:高内存地址放整数高位,低内存地址放整数低位(高高低低)简称:倒着放(代表:X86,ARM)
大端对齐:高内存地址放整数低位,低内存地址放整数高位(高低低高)简称:正着放(很多unix服务器都这样)
举个栗子:int i=0x12345678;
之前也有想了解这些,第一个不是学底层的不知道从何理解,第二个上网搜概念,大牛们三言两语就结束了,举得例子也比较复杂,对于非C方向的可能有点吃力,所以一直没理解。还有些网上的根本是胡说,妄以揣测,不能据理力争
今天偶然发现原来还有内存窗口之说,就慢慢的打开了思路,形成了自己的理解,有不当之处欢迎指出,小子感激不尽
进入正文:
调试的时候先打开内存窗口:
监视一下i的地址,在内存窗口里面找到这个值,发现里面有个32(50转换成16进制就是32)
验证一下下面的确是16进制
我的理解是:
这次把int改成16进制再看看调试结果:CPU是x86、ARM架构基本上都遵循 小端对齐(高地址放高位,低地址放低位)
图中很明显,内存地址越下面的越大(0x0018FBF4 > 0x0018FBB8),我们监控的地址明显是低地址
0x12345678,高位是1,低位是8。我画张转换图
然后解释下,为什么占了4个
int,占4个字节(byte),而1byte=8个bit
所以看图:
再根据低低高高的原则,就是这样放了
验证一下我的想法:(1不够了,所以用0补)
内存中存的是2进制的数,现在我们进行逆推,自然就有了这幅图:(内存最小单位byte)
吐槽一下,尼玛,上学一直不太明了的东西,在VS这个神器下竟然解决了!!
扩展:(X86,ARM一般都是小端对齐,很多Unix服务器用大端对齐)
内存地址位数其实也有讲究,把VS切换到X64下,发现内存地址也长了许多
X86的是8位,也就是1byte,同理可推X64的是2byte(各个环境不同这个值可能不太一样)
之前说到了long的争议(http://www.cnblogs.com/dotnetcrazy/p/8059210.html),这边就不用long来举例了,用int吧
可以看一下这篇文章(http://www.cnblogs.com/dotnetcrazy/p/6743530.html),更好理解本文(本文不继续探讨大小端对齐问题,只研究标题内容)
1.基础就不详解了贴张图:
说一下QWORD,之前也被网上误导了,网上很多都是说无符号的word,按照惯例,如果是unsigned word,那么所占字节应该和word一样才对
验证:有无符号,他所占字节并不变
后来发现Win10最新版有一计算器神器(你们可以通过应用商城装)===》
通过7来说说这些“字”宝宝们(我后面说补码计算的时候也会用到这个案例)
1Byte=8bit(一个二进制位就是一个bit)
7==》0000 0111
1WORD=2Byte,7==》0000 0000 0000 0111
1DWORD=4Byte,7==》0000 0000 0000 0000 0000 0000 0000 0111
重点来了,要是QWORD真的是WORD无符号字,那么应该和WORD一样只占2Byte
然而事实==》打脸打的PaPa响,1QWORD=8Byte,7==》以下省略一千字
2.原码,反码,补码
在计算机内,有符号数有3种表示法:原码、反码和补码
原码:计算机中对数字的二进制定点表示方法。最高位为符号位(正数该位为0,负数该位为1)其余位表示数值的大小
反码:正数的反码与其原码相同,负数的反码:符号位不动,其他取反
补码:正数的补码和原码相同,负数的补码:符号位不动,其他取反,最后+1(相当于:补码+1)
补码的好处:使符号位能与有效值部分一起参加运算,从而简化运算规则;
来张图更直观:
来来来,实践验证一下:
分析:按照求负数补码的逆过程,数值部分应是最低位减1,然后取反。 但是对二进制数来说,先减1后取反和先取反后加1得到的结果是一样的,故仍可采用取反加1 的方法。
这些都比较简单,下面说下补码的好处:
体验分析一下
7-6=1;-7+6=-1
7-6=1
7补码:0000 0111
-6补码:1111 1010
0000 0111
1111 1010
---------
1 0000 0001
相加之后进位舍弃(总共就8位,溢出就没了),0000 0001==>1(正数的补码是他本身)
-7+6=-1
-7补码:1111 1001
6补码:0000 0110
1111 1001
0000 0110
---------
1111 1111
相加之后木有进位,补码:1111 1111==>正码(符号位不动,其他取反,最后+1):1000 0001==> -1
扩展(有兴趣的可以自己研究一下补码的各种溢出):https://baike.baidu.com/item/反码#5
3.整数溢出探讨
intmax=0x7FFFFFFF; (2147483647)
不清楚的可以看这个图,第一位是符号位,后面是数值部分,所以第一个最大是7,其他最大是F
借用Net里面的Int.Max验证下:2147483647
不高兴搞需的,毕竟不是学生了,直接跑个程序看看
int main() {
int i = 0x7fffffff;
printf("i=%X==>%d\n", i, i);
i += 1;
printf("i+1=%d==>%X\n", i, i);
return 0;
}
CentOS_X64:i+1=-2147483648==>0x80000000
Win10_X64:i+1=-2147483648==>0x80000000
记得以前学生时代就很不解,老师也说不清楚,这次看见了就研究了下
来来来,Net来个福利:自己研究下为啥
不扯了,二进制走一个:(二进制是不管符号位啥的,输出的八进制和十六进制其实都是unsigned int (%o,%x))
0111 1111 1111 1111 1111 1111 1111 1111
+1
1000 0000 0000 0000 0000 0000 0000 0000
———— ———— ———— ———— ———— ———— ———— ————
8 0 0 0 0 0 0 0
intmax+1=0x80000000,程序员还是比较喜欢十六进制啊~方便
可能你还没转过来,(⊙o⊙)…,好吧,我们用补码的方式再算一遍
0111 1111 1111 1111 1111 1111 1111 1111
0000 0000 0000 0000 0000 0000 0000 0001
---- ---- ---- ---- ---- ---- ---- ----
1000 0000 0000 0000 0000 0000 0000 0000
转为正码: 1000 0000 0000 0000 0000 0000 0000 0000 补码 1111 1111 1111 1111 1111 1111 1111 1111 正码
2^31==>2147483648,符号位是1,则最后结果是-2147483648
------------------------------------------
收工了,感兴趣的可以用Win10计算神器看看(用QWORD又是怎样呢,可以自己思考,很有意思哦)
[Ubuntu的计算器编程模式也一样有这个功能,就是页面丑了点]
稍微解释一下:word是2Byte,intmax是4Byte,所以不够放
在选下HEX,输入运算得到的数字