005_为何64位下一个指针大小为8个字节和32/64位系统的关系

一、通俗理解指针

说到指针,首先我们得开始从变量说起(或者常量,以下均用变量进行说明),如果你实现下面代码:int a = 10; 最终转成汇编的底层内存布局就是,在某一块存储空间里存储着10这个数值,这块存储空间会根据变量声明的不同地方而相应存储在全局区(也是常说的数据段)、栈区(一般是声明在一个函数或者方法里),以及堆区(堆区的话,常见的就是放在堆空间里的一个类对象的属性)。而怎么能够找到存储着这个10的存储空间呢,就是通过内存地址找到的,假如这个内存地址是0x100000800,而通过这块内存地址找到的存储空间里存储的东西,就是那个10,一般的,一个变量都是会占用一定大小的空间来存储,假如,在这儿的int默认分配4个字节,那么在0x100000800到0x100000803这段里存储着的就是这个数值10。看到这儿,大家应该也清楚明白了,其实这0x100000800仅仅是存储着10的这段存储空间的首地址而已。

好,接下来,要说明白的就是指针了。我为何要花这么长一段话来讲解这个普通的变量呢,就是因为,我们常说到和用到的指针,都是通过变量来使用的,就是常见的指针变量。通过上面对普通变量的理解和认识,我们已经清楚的知道了,一个变量,会有相应的一段存储空间来存储着相应的值,例如,上面的int a = 10  这段存储空间里,存储的就是10这个数值。而我们接下来要说的指针,int *b  = &a  ,  他这段存储空间里,存储着的东西就不是10了,但是也是一个数值,这个数值就是一个地址值,这个地址值里就存储着10。我们这里假如a的存储空间的首地址是0x100000900,存储着10的那块内存空间是0x100000800,那么这里a的存储空间里存储的那个数值就是0x100000800,之后再根据这个0x100000800地址值找到他里面存储着的10,下图是对int a = 10以及int *b = &a 的具体图解:

 

我们简单的对上面的做个描述:

int a = 10时,会分配一段存储空间给a,这段存储空间里存储着的数值就是10

int *b = &a 时,同样会分配一段存储空间给a,这里面存储着的也是一个数值,只是这个数值是个地址值。之后还会分配另一段存储空间,这段存储空间里,存储着的就是10。之后,a存储空间里存储着的地址值就是存储着10的那段存储空间的首地址值。那如何访问这个10呢,就是通过a里存储着的地址值寻找到存储着10的那段存储空间,之后就能访问了,代码就是:*b

代码示例如下:

#include <stdio.h>
int main(int argc, char *argv[]){
    int a = 10; 
    int *b = &a;

    printf("&a:%p, b:%p, a:%d, &b:%p\n", &a, b, *b, &b);
    return 0;
}/*
$./a.out 
&a:0x7fffd7404d2c, b:0x7fffd7404d2c, a:10, &b:0x7fffd7404d30
*/

二、为何64位下一个指针大小为8个字节?

通过上面的介绍,我们对指针有了个清楚的认识。那么,随之就引入了本篇文章的重点了,为何64位下一个指针大小为8个字节。其实,这个原因也是很简单的,只是可能很多小伙伴从没去想过这个问题,所以当问到这个问题的时候,可能就是一脸懵逼,当然,我第一次被问到这个问题的时候也是一脸懵逼,哈哈哈。

现在先引入一个计算机常识,那就是,无论是什么类型的指针变量,在32位系统下,一个指针变量所占用的空间是4个字节,在64位下,一个指针变量所占用的空间是8个字节。

那么为何会是这个值呢?就听我给你细细讲来。

首先,我们得知道另一个计算机常识,那就是,一个字节(byte)占用多少位(bit),没错,是8位。这里,你可能会发现一个有趣的地方,32 bit == 4 byte , 64 == 8 byte。这不是巧合,哈哈哈。

现在我问你一个问题,64位能表示的数值个数是多少?很简单,2^64个,数值范围就是从0到2^64 - 1,这也是如今64位CPU的寻址范围,用16进制表示就是:0---FFFF FFFF FFFF FFFF(F是数值15,二进制就是1111,刚好是四位,所以2个16进制位就是一个字节),那么重点就从这儿开始了,如果想让一个指针变量存储的数值能表示完所有的寻址范围(也就是所有的地址值),那么毋庸置疑,他的存储空间必须是大于等于64bit,也就是8个字节,少一个bit,都不能完整的表示完所有的寻址范围,刚好,8个字节刚好能不多一位不少一位的表示完所有的寻址范围,因此就是8个字节。同理的32位下就是4个字节

三、附加解释

这里再给你普及一个知识点,就是值的存储

问你个问题,一位能表示的最大值是多少?没错,是1,也就是2^1 - 1,一位能表示的数值个数是2^1,言下之意就是,如果你想存储一个数值,只有0和1的话,那么一个bit的足矣,同理,如果想存储一个255的话,那么8个bit足矣,也就是一个字节,那么要存储2^64 - 1,那就得64位,八个字节

当然,还有就是数值存储最终会是用补码进行存储的,为何如此,我就提下其中一个原因,这里不做多余的解释,原因就是为了能让在负数存在的情况下,每一个数值都能对应着唯一的一个2进制数。简单说下,如果用原码存储的话,正0和负0对应着两个不同的二进制数,用16进制表示的话,正0是:0000 0000 0000 0000,负0是:8000 0000 0000 0000(也就是最高位符号位是1)。如果是补码的话,正0和负0都是用对应着同一个二进制数,用16进制表示的话,也就是0000 0000 0000 0000

 

四、32位/64位系统支持内存比较

32位系统

32位系统使用32位地址线的最大寻址空间为2的32次方bytes,计算后即4294967296 Bytes,也就是我们常说的4096MB,32位地址线的寻址空间封顶即为4GB。但是,虽然系统能够识别4096MB,我们还是不能完全使用它,像显卡也需要占用一部分内存,而这部分内存通常是直接划归显卡使用,不会显示在系统中,部分主板的BIOS设置中可以找到这样的选项。 32位Windows 7/8系统支持的最大内存事实上只有3.25GB左右,另外32位系统在应用程序占用内存上面还存在限制,通常会限制单个应用程序占用内存不能超过2GB以上,如果超过就会发生内存溢出现象。

64位系统

64位系统使用64位地址线的最大寻址空间为2的64次方bytes,计算后其可寻址空间达到了18446744073709551616 Bytes,即16384PB(PebiByte)或16777216TB(TebiByte)。但是,很多64位CPU使用40位地址线,最大寻址空间仅为1TB,加之别的种种原因,目前Windows 7 64位版最大仅能使用192GB内存,Windows 8 64位版最大仅能使用512GB内存。不过尽管系统所能支持的内存有这么大,但主板和CPU的限制导致一般的电脑所支持的内存最大只有16GB而已。

 

Reference:

https://blog.csdn.net/qq_20255275/article/details/99692336

 

posted @ 2021-01-27 11:15  arun_python  阅读(689)  评论(0编辑  收藏  举报