在很早的时候,我知道计算机存储单元是BYTE,一个BYTE是8位。但在我的脑海里还是有模糊不清楚的地方。
PS:通常我们说32位计算机,指计算机CPU一次能处理的数据宽度是32位,那是不是就是说数据总线上32位的呢?
32位计算机,地址总线32位,能访问的最大地址是2的32次方,所以说4G内存,也就是一般我们知道的32位机器能支持的最大内存数。
我的计算机上32位的,现在装了2根2G的内存条,就是即使再加内存条也是没有的。
那么我就有这样的疑问:32位表示的某一个地址,那个地方是不是可以用32个二进制数表达一个数呢?因为数据宽度是32位呀。就是4个字节。
定义两个int类型数据,第二个数据的地址跟第一个的地址,只会相差1,有一个偏移。
事实上这样么?事实不是,他们地址偏移是4.
之前我有做过测试,sizeof(int),char等数据类型占用的内存分配。
其实当时对于一个存储单元的理解是模糊的。
再次来做测试。
int i=1;
int j=2;
printf("int占用的字节数%d\n",sizeof(int));
printf("i的地址%p\n",&i);
printf("j的地址%p\n",&j);
这是一个很简单的程序。
测试结果如下图
(图片1screen:i=1;j=2)
采用的编译器是GCC,IDE是code block.我在codeblock里面观察memory。因为我已经输出地址栏,所以知道这两个变量存放的地方,去看memory里的内容。
如下图,memory
(图片2memory i=1 j=2)
两个相邻的变量定义,分配了两个地址空间。可以知道先定义的变量i的地址是高地址,j是低地址,低了4byte.
也就是4个存储单元。
这里我们清楚的看到,一个地址对应一个存储单元,而这个存储单元是8位的(因为memory是以16进制显示的,最大可显示ff).
而地址0x22ff3c,存储单元的内容是1.就是我们初始化的值。
0x22ff38,存储单元的值是2.
我还有别的疑问,单纯学习C语言的可能对这些不感兴趣,而我自己希望了解计算机运作原理,c是最接近底层的高级语言,所以才用C语言帮我理解计算机原理。
我现在的疑问是,int i,占用4个字节,那么是从0x22ff3c往高地址计算(图片memory上的右边)的4个字节,还是往左边,就是低地址呢?
更确切来说,0x22ff3c,0x22ff3d,0x22ff3e,0x22ff3f这四个存储单元,还是0x22ff3c,0x22ff3b,0x22ff3a,0x22ff39. 再往地址低处,就是0x22ff38,这个就是j的起始地址栏。
从j后定义,分配的地址比i低,我们可以大胆猜测,是往低处计算的,就是0x22ff3c-0x22ff39.
但这是我的猜测,我希望验证下。
怎么验证呢?我想到一个方法,C语言int类型可以表示的数据范围是(-2的31次方)int i=1int i=1到(2的32次方-1).
我把i初始化为一个比较大的数,至少大于一个byte能表示的最大数255就可以了。我真是太机智了,当初大学时候对C语言一塌糊涂。
再次测试。把i初始化为256,j呢,初始化为负数吧,还可以观察下负数在计算机的存储。
代码如下(其实代码基本无变化)
int i=256;
int j=-1;
printf("int占用的字节数%d\n",sizeof(int));
printf("i的地址%p\n",&i);
printf("j的地址%p\n",&j);
观察memory,图片如下2memory
(图片3memory i=256,j=-1)
好吧,memory告诉我,我猜测错误,j=-1,在计算机 内以补码存储,正是0xffffffff.地址是从0x22ff38到0x22ff3b
i=256,原码等于反码等于补码,存储为0x100;地址是从0x22ff3c,0x22ff3d,0x22ff3e,0x22ff3f.
而这个显示是 00 01.
也告诉我们memory里每一个存储单元,右边的都是低位,所以01,这个1 是二进制表示的时候,从右边数第三位。
那我做一个测试吧,给i 初始化为int所能表示的最大的数,2147483647(0x7fffffff)
因为最高位是符号位。
测试时候memory里存储如下。
图片显示不出来么?
如果初始化的时候,超过最大值呢?
测试下,结果
在memory里存储是0x80000000,不计算符号位的时候,是2147483648,但是printf的时候,显示的是如下图
是带符号位的,0x80000000(1000 0000 0000 0000 0000 0000 0000 0000),补码表示的二进制数-2147483648.
(符号位不变,数值位取反得到1111 1111 1111 1111 1111 1111 1111 1111,再加1得到 1 0000 0000 0000 0000 0000 0000 0000 0000,是2的31次方,记得前面的符号哦,是负的).这是最小的负数了。
然后我把int初始化为int i=2147483649; memory里显示的是 01 00 00 80(也就是80 00 00 01),运行程序,输出i的值是-2147483647.
然后我把int初始化为int i=4294967295;(memory里是ffff ffff ),运行程序i=-1;
这个结果与我们初始化j=-1在memory 里存储的是一样的。
由此可以理解了int 数据在内存中的存储问题。
这是我们亲自测试过的,获得的理解与单纯看书是完全不一样的。
最后一个问题,我们的题目有说《兼论大端模式和小端模式》,那么首先要理解名词,大端模式与小端模式。
大端模式(Big-endian):字数据的高字节存储在低地址。而字数据的低字节存储在高地址。
小端模式(Little-endian):字数据的高字节存储在高地址,而字数据的低字节存储在低地址。
这个对于我们理解内存有影响么?其实是没有的,只不过是两种命名而已,就像《格列佛游记》一个地方为了吃鸡蛋先吃大头还是小头的问题吵个不休。
但是我们既然在研究,看下我现在的计算机是先吃鸡蛋大头还是小头呢?我们在上文int i=256的时候,数据的存储图片还在上面图片3(i=256,j=-1)
i=256的时候(16进制表示0x01 00)高字节01是放在地址0x22ff3d,而低字节00是放在0x22ff3c上。那就是高字节放在高地址,低字节放在低地址,小端模式。
当然呢,这个名字呢,不要纠结,老子说“道可道,非常道,名可名,非常名”----白马非马,焉知鱼之乐乎!
这是我新年上班第一天的研究的问题。以此记录。