不同平台下int类型、指针类型的数据大小

对于int类型数据和指针类型数据的大小,是非常基础的问题。

在一个具体的平台上,确定他们最好的办法就是使用sizeof(type)对其进行判断,返回当前数据类型的大小。

在不同的平台下,int类型和指针类型的数据类型大小时怎样的呢?如果要给出一个统一的答案,自然不可能集齐每个平台,一个个地去试,我们必须从底层进行分析。

数据总线和地址总线

计算机内的数据总线是CPU与外设进行数据交换的通路,而地址总线则是CPU用于寻址的通路。

数据总线的位数决定了CPU与外设一次可以传输的字节数。

而地址总线则决定了CPU可以寻址的范围,如果是32位地址线,每根地址线传输一位,可表示的范围为02^32-1,由于内存中的基本单位是byte,所以也就对应02^32-1 byte,也就是0~4GB,对应于内存的可取范围。

总线的位数一般也用总线宽度来表示。


一个常见的误区是:地址总线和数据总线的宽度总是保持一致的。

这个错误想法的缘由就是没有弄清楚地址总线和数据总线的工作原理,我们可以这样理解:

在一个很大的仓库中,地址总线代表一张仓库地图的坐标,而数据总线则是取货的推车,地图坐标系的大小(也就是地址总线的宽度)决定了它可以记录多大的仓库面积,而推车的大小(即数据总线的宽度)决定了一次可以取多少货。

仓库管理员根据地图找到货物存放的地址,然后使用推车来存取货物。

在这个模型中,仓库的面积可以非常大,只需要将地图坐标绘得足够大,而取货的推车可以很小,只是取大件货物的时候多跑几次。

同样的,管理员可以买个足够大的推车,而仓库面积并不大,只是通常在取货的时候,推车不能被装满,存在一些空间浪费问题。


所以说,地址总线和数据总线在宽度上没有太大的联系,但是,芯片设计者为了平衡时间效率和空间效率,同时考虑到硬件上的影响,通常使用同样的地址总线宽度和数据总线宽度。

举一个数据总线和地址总线宽度不同的例子:在经典的8086计算机中,数据总线为16位,地址总线则是20位。

芯片的位数

通常,我们所说的一个芯片是多少位的,到底是看它的数据总线宽度还是地址总线宽度呢?

答案是:决定一个芯片多少位,是由这个芯片一次能处理多少位数据决定的,等于片内寄存器的宽度,同时可以看成是数据总线的宽度。

为什么这里说的是芯片位数可以看成是数据总线的宽度而不是等于数据总线的宽度呢?按照目前的情况而言,几乎所有的芯片位数都等于数据总线宽度。

但是从严格意义上来说,数据总线是用来传输数据的,芯片位数指的是处理数据的宽度,数据的传输和处理并非同一个概念,传输和处理数据的宽度是可以不一样的,只是实际情况下数据传输的宽度和处理的宽度是一样的,当然,这种区分有点吹毛求疵,所以,芯片位数等于数据总线宽度也是一种可接受的答案(当然,过去都是一致不代表未来也是一致,概念还是要分清)。

同时,在编程时,我们通常碰到一个叫做"字长"的概念,字长通常等于数据总线的宽度。

int型数据的大小

常见的第二个误区是:int型数据的大小,也就是sizeof(int)的大小完全跟随硬件平台的位数。

这个误区的产生是源于我们初学C语言时的教程:在16位芯片上int型类型大小为16位,即两字节,而在32位机器上,int型为32位,即四字节。 以此类推,由此我们就建立的一个模糊且错误的概念:int型数据的大小是跟随于平台的位数。

事实上,正确的答案是:int型数据的大小和硬件平台位数无关,它是由C语言标准和编译器共同决定的。

为此,博主查阅了C99 spec标准,它是这么说的:

Sizes of integer types <limits.h>
The values given below shall be replaced by constant expressions suitable for use in #ifpreprocessing directives.
...
...
minimum value for an object of type int
INT_MIN -32767 // −(215 − 1) //这只是其中一个示例,不同平台可能有不同定义
— maximum value for an object of type int
INT_MAX +32767 // 215 − 1

翻译过来就是,int类型的大小是由limits.h文件中INT_MIN和INT_MAX两个宏定义来决定的,而limits.h文件在编译器库文件中可以找到。

int类型对应平台的大小是这样的:

  • 16位系统中,int型为16位大小,两字节
  • 32位系统中,int型为32位大小,四字节
  • 64位系统中,int型为32位大小,四字节

事实上,除了int类型,还有一个类型在不同平台中有不同的表现,那就是long型:

  • 16位系统中,long型为32位大小,4字节
  • 32位系统中,long型为32位大小,4字节
  • 64位系统中,long型为64位大小,8字节

指针的大小

对于指针变量的大小,我听得最多的一个概念就是:在32位系统下指针类型为32位,在64位系统下指针类型为64位,以此类推。

但是不得不遗憾地说,这个说法其实是错误的,至少说是不严谨的。

指针本质上是变量,它的值是内存中的地址,既然需要通过指针能够访问当内存当中所有的数据,那么这个指针类型的宽度至少要大于等于地址总线的宽度。打个比方一个芯片的地址总线是32位,那么内存地址的范围就是0~4G,那么这个指针类型的宽度至少需要32位,才能保证访问到内存中每个字节。

但是,实际上的情况是:芯片的位数由芯片一次能处理的数据宽度决定,可看成是数据总线的宽度,但是地址总线和数据总线的宽度有时候并不一致。

所以在经典的32位系统中,同时也是32位地址总线,自然而然的,指针的长度为32位。

但是对早期的8086而言,这是16位芯片,但是它的地址总线却扩展到了20位,同时因为数据对齐的原因,它的指针大小应该是16+16位=32位,但是出于效率上的优化,8086提供了远指针、近指针,在访问本段内的地址时,采用16位指针,如果有段地址跳转,就使用32位的指针。

至少从这个示例可以知道,指针的大小完全由实际使用的地址总线的宽度(+数据对齐)来决定,而并非由芯片位数来决定。

所以,有时候,我们可能会在64位系统中碰到指针大小为4字节的情况,也可能在16位系统中碰到指针大小为4字节的情况。

当然,需要特别注意的是,在64位系统中地址大小为4字节的情况下,并非一定是芯片的地址总线是32位,很可能是CPU运行在只使用部分地址总线的模式下,又或者是使用32位兼容的编译器所致,这一部分较为复杂,本文旨在建立一个初步的概念,如果要深入研究的话几篇博客是不够的,这里暂不赘述。

总结

int和long类型数据大小并非由硬件平台的位数决定,而是由C标准和编译器共同决定。

同时,指针即sizeof(ptr)的大小也并非由硬件平台的位数决定,而是由实际上所使用的地址总线宽度决定的。


好了,关于int型和指针的大小的讨论就到此为止啦,如果朋友们对于这个有什么疑问或者发现有文章中有什么错误,欢迎留言

原创博客,转载请注明出处!

祝各位早日实现项目丛中过,bug不沾身.

不同平台下int类型、指针类型的数据大小的更多相关文章

  1. 《精通C#》自定义类型转化-扩展方法-匿名类型-指针类型(11.3-11.6)

    1.类型转化在C#中有很多,常用的是int类型转string等,这些都有微软给我们定义好的,我们需要的时候直接调用就是了,这是值类型中的转化,有时候我们还会需要类类型(包括结构struct)的转化,还 ...

  2. golang(3):strings和strconv使用 & 时间和日期类型 & 指针类型 & 流程控制 & 函数

    strings和strconv使用 . strings.HasPrefix(s string, prefix string) bool: // 判断字符串s是否以prefix开头 . . string ...

  3. golang中值类型/指针类型的变量区别总结

    转自:https://segmentfault.com/a/1190000012329213 值类型的变量和指针类型的变量 先声明一个结构体: type T struct { Name string ...

  4. 在linux平台下,设置core dump文件属性(位置,大小,文件名等)

    在linux平台下,设置core dump文件生成的方法: 1) 在终端中输入ulimit -c 如果结果为0,说明当程序崩溃时,系统并不能生成core dump. 2) 使用ulimit -c un ...

  5. 对于C语言复杂指针类型的分析

    转载自:http://www.slyar.com/blog/complicated-point-type.html int p; p是一个普通的整型变量. int *p; 1.p与*结合,说明p是一个 ...

  6. C++指针类型识别正确姿势

    指针是C和C++中编程最复杂也是最有技巧的部分,但对于新手来说,指针无疑是最致命的,让很多人望而退步.不过很多事情都是从陌生开始,然后渐渐熟悉起来的,就像交朋友一样,得花点时间去培养感情才行.不过指针 ...

  7. C语言指针类型

    1:只要是指针类型,不管是几级指针[带几个*],其宽度都是4字节 2:任何数据类型[包括自己定义的结构体]前面都能加*号,表示该数据类型的一个指针 3:由于是386处理器,其数据处理的宽度都是四个字节 ...

  8. 编程范式 epesode7,8 stack存放指针类型and heap,register

    这一节从后往前写. ____stack and heap ___stack由 汇编语言操控管理,数据先入后出. 栈是存放局部变量,函数调用子函数时,该函数在栈中占用的空间会增大,用于存放子函数的局部变 ...

  9. Swift中对C语言接口缓存的使用以及数组、字符串转为指针类型的方法

    由于Swift编程语言属于上层编程语言,而Swift中由于为了低层的高性能计算接口,所以往往需要C语言中的指针类型,由此,在Swift编程语言刚诞生的时候就有了UnsafePointer与Unsafe ...

随机推荐

  1. CF1175D Array Splitting

    题目链接 题意 给出一个长度为\(n\)的序列\(a\),要求分为恰好\(K\)段.第\(i\)个点的贡献是\(a_i \times f(i)\),\(f(x)\)表示x所属的是第几段. 思路 非常巧 ...

  2. H5 + 3D + AR/VR 综述

    近年来,H5,3D,AR,VR逐步进入人们的视野,H5生动活泼,3D注重视觉效果,AR打造虚实结合,VR则更加注重虚拟现实的产生. 第一部分,案例展示: H5+VR案例: 故事<不要惊慌,没有辐 ...

  3. Python程序设计例题

    例一:蒙特卡罗方法求解 π 值 from random import random from math import sqrt from time import clock DARTS=1000 hi ...

  4. elasticsearch 7.5.0 学习笔记

    温馨提示:电脑端看不到右侧目录的话请减小缩放比例. API操作-- 新建或删除查询索引库 新建索引库 新建index,要向服务器发送一个PUT请求,下面是使用curl命令新建了一个名为test的ind ...

  5. Maven使用第三方Jar文件

    本例中,需要在Maven项目里添加uiautomator.jar文件.以下介绍两种方法: 方法一:在pom.xml里指定jar文件目录 <dependency> <groupId&g ...

  6. 收藏一份devmem源码

    /* * devmem2.c: Simple program to read/write from/to any location in memory. * * Copyright (C) 2000, ...

  7. ros脚本断点调试-编写过程可以把过程变量输出到log查看的方法

    /caps-man registration-table :do {:foreach i in=[find interface~"5G"] do={:log info messag ...

  8. vertica ROS和WOS错误

    频繁写入vertica,可能导致ROS和WOS错误.如下: java.sql.SQLTransientException: [Vertica][VJDBC](5065) ERROR: Too many ...

  9. C#:ref关键字和out关键字的区别

    1.在不使用关键字(比如ref关键字.out关键字等)修饰函数的情况下,大部分函数的参数是以值传递的方式,也就是说,“调用函数”在使用参数(比如myNumber)时,是把该参数复制多一份,然后将其传递 ...

  10. MongoDB 学习笔记 ---创建用户

    MongoDB安装好了之后,开始学习常用命令 首先,运行MongoDB, 记住,先不用带参数--auth /usr/local/mongodb/bin/mongod -dbpath=/usr/loca ...