一个简单程序思考计算机里int数据的存储问题,兼论大端模式和小端模式

     在很早的时候,我知道计算机存储单元是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上。那就是高字节放在高地址,低字节放在低地址,小端模式。

当然呢,这个名字呢,不要纠结,老子说“道可道,非常道,名可名,非常名”----白马非马,焉知鱼之乐乎!


这是我新年上班第一天的研究的问题。以此记录。












  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值