菜鸟资源网站全面焕新升级啦!全新的界面设计,简洁而不失雅致,让您一目了然,轻松上手。我们还对资源分类进行了细致梳理,确保各类资源条理清晰,便于您按需筛选与查找。 立即查看

第五章:计算机是如何存储变量的,了解C++基本语言特性变量和类型

第五章:计算机是如何存储变量的,了解C++基本语言特性变量和类型

  变量是所有程序的基础,类型告诉编译器数据代表什么意思以及可对此数据执行的操作。例如int类型的数据可以执行加减法,而bool类的数据就不能进行加减法。这些都是数据类型规定的。C++语言定义了几种基本类型:字符类型、整型、浮点型等,除此之...

当前版本

软件大小

软件语言

是否破解

  变量是所有程序的基础,类型告诉编译器数据代表什么意思以及可对此数据执行的操作。例如int类型的数据可以执行加减法,而bool类的数据就不能进行加减法。这些都是数据类型规定的。C++语言定义了几种基本类型:字符类型、整型、浮点型等,除此之外,C++还提供了可用于自定义类型的机制,如可自定义类类型。变量和类型是C++语言基础的概念,同时也是编程中最容易疏忽的地方。本章将介绍变量和类型的相关概念和编程陷阱。通过本章的学习,希望能帮助你对变量和类型有更深刻的认识。

第五章:计算机是如何存储变量的,了解C++基本语言特性变量和类型

计算机是如何存储变量的

  众所周知,计算机界一直存在这样一个共识:编程=数据+算法。从这个共识可以看出,程序其实就是实现数据的处理,及解决如何处理数据的问题。高级语言能处理的数据一般都存放在内存中,程序如何高效地处理数据,这与数据在内存中的存储情况息息相关。特别是C/C++语言,要想运用好它,就必须对数据在内存中放置及存放格式有详细的掌握。数据在内存中的放置包括两个部分:一是数据放置的位置,二是数据放置的格式。数据放置的位置,即数据存储的区域。C++可执行程序的数据存储区域可分为只读数据区、全局/静态存储区、自由存储区、栈区和堆区5种。下面这段代码就涵盖了所有数据存储区域类型

  就涵盖了所有数据存储区域类型。

  int g_init var =100;     // 初始化的全局变量g_init_var=100
  int g_uninit var;        // 初始化的全局变量g uninit var
  void Func(init)          // 输出一个整数到屏幕
  {
      printf("%d\n", i);
  }

  int main(void)
  { 
      static int static var= 101;    // 初始化的局部静态变量static_var=101
      static int static var2;        // 未初始化的局部静态变量 static var2

      intnNumber=1;                  // 初始化的局部变量nNumber=1
      intnNumberB;                   // 未初始化的局部变量nNumberB

      // 输出 static_var、static_var2、nNumber、nNumberB 的和到屏幕
      Func(static var+static var2+nNumber+nNumberB);

      char *pszstrLG="liuguang";    //指向常量 liuguang 的局部指针变量 pszstrLG
      char *pszStr2=new char;       //指向堆区的内存的局部指针变量 pszSt2
      delete pszStr2;

      int*pnNumber=static_ cast<int*>(malloc(sizeof(int));  //分配在自由存储区的pnNumber
      free(pnNumber);

      return 0;
  }

  ●只读数据区:存储常量和恒值。例如,上述代码第 019 行的字符串 liuguang 就分配于只读数据区。存储于只读数据区的变量一般不允许修改。当然所有的数据都是相对的,可通过一些非正常手段修改只读数据区。

  ●全局/静态存储区:全局/静态存储区主要存储全局变量和静态变量。在C语言中,全局变量又分为初始化的全局变量和未初始化的全局变量,初始化的全局变量和静态变量存储在data区,未初始化的全局变量与静态变量存储在相邻的 bss区,而在C++里面没有这个区分,它们共同占用同一块内存区。例如,上述第001、002、011、012行代码中所涉及的变量均分配在全局/静态存储区。

  ●自由存储区:自由存储区是指 CRT(C 运行时库)通过 malloc、free 函数管理的内存。在部分编译器的实现上,自由存储区和堆两块内存都是同一种管理方式,所以可统称为堆区。例如,上述代码第 023行 pnNumber 变量对应的内存块即自由存储区。

  ●栈区:栈区中存储的数据由编译器自动分配释放,主要存放函数的参数值、局部变量值等。其操作方式类似数据结构中的栈。栈区在分配数据时,地址自动对低地址增长。在程序执行过程中,栈可以动态地扩展和收缩。一个函数的栈空间大小一般为 2MB。当然函数的栈空间大小可通过设置编译选项修改。在一个进程中,位于用户虚拟地址空间顶部的是用户栈,编译器用它来实现函数的调用。用户栈在程序执行期间也可动态地扩展和收缩。例如,上述代码段中第014、015行的nNumber 和 nNumberB就分布于栈区中。

  ●堆区:堆区指那些由 new 分配的内存块,编译器不负责它们的释放。上述代码中第 020 行 pszStr2所指的内存块就分配在堆区。分配在堆区的变量由应用程序去控制,一般一个 new就要对应一个delete。如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收。堆区可在程序运行过程中,根据需要动态地申请和释放。堆区的这种操作特性可节省数据存储空间。

  注意:堆区分配数据虽具有节省空间、使用方便灵活的优点,但并不是说所有的变量都应该分配在堆区。堆区上分配数据有两个风险:

  (1)频繁分配和释放内存会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低,

  (2)分配的数据如果没有释放,很容易造成内存泄露。这是在C++初学者中普遍存在的问题.

  C++中的所有数据都通过这5种数据类型实现数据的存储和分配。这5种数据存储类型的内存布局如图2-1所示。

第五章:计算机是如何存储变量的,了解C++基本语言特性变量和类型

  介绍完数据的存储位置,接着介绍数据的存储格式。因为任何数据都是以一定格式存储的,只有这样才能被CPU 及编译器识别,所以了解数据的存储格式也是掌握数据类型较为关键的部分。C++内置的数据类型有整型和浮点型,编程人员可自定义的类型有class、struct 等。

  1.整型值

  整型值是程序员处理和操作最多的数据,表示整数、字符型和布尔值算术类型合称整型。

  字符类型有两种:char 和wchar_t。char 主要存储机器基本字符集中任何字符相应的值,因此 char 通常是单字节的。wchar_t 类型用于存储扩展字符集合,由于扩展字符集中的字符不能用一字节表示,所以wchar_t通常是双字节的。

  int、short、long 类型都表示整型值,不同之处是存储变量所占的内存空间大小不同。short类型一般为半个机器字长,int 占一个机器字长,long占一个或两个机器字长。

  整型存储说明:

  整型与其在计算机存储中的表示方式密切相关。计算机以位序列存储数据,每一位存储0或1,通常以8位块作为一字节,32位或4字节作为一个“字(word)”。

  大多数的计算机将存储器中的一字节和一个称为地址的数关联起来。要让存储器中某一地址的字节有意义,必须知道存储在该地址的值的类型。

  bool类型表示真值 true 和 false。可将算术类型的任何值赋给 bool 对象,0 值代表false,非 0 代表 true。除 bool 类型外,整型可以是有符号的(signed),也可以是无符号的(unsigned)。整型 int、short、long 默认都是带符号型。整型以二进制补码形式存储,其中正数等于原码,负数等于反码+1。例如,100的原码为 0x64,在内存中存储的补码为 0x64;-1的原码为0x01,反码为0xFE,在内存中存储的补码为0xFF。表2-1列出了所有整型值的类型、字节长度和可能的取值范围。

表2-1  整型数据取值范围

整型类型占用字节取值范围
(signed) char1-128~127
unsigned char10~255
(signed) short2-32768~32767
unsigned short20~65535
(signed) long4-2 147 483 648~2 147 483 648
unsigned long4~4 294 967 295
(signed) int4-2 147 483 648~2 147 483 648 
unsigned int40~4 294 967 295
bool1true/false

  2.浮点类型

  C++对浮点类型的数据采用单精度类型(float)和双精度类型(double)存储.float数据占用32bits,double 数据占用64bits。无论是单精度还是双精度,在存储时,都分为3个部分:(1)符号位(Sign)占用1字节,0代表正数,1代表为负数;(2)指数位(Exponent),用于存储科学计数法中的指数数据,并且采用移位存储;(3)尾数部分(Mantissa)。

  float 的存储格式如图 2-2 所示,指数位采用移位存储,偏移量为 127。采用图 2-2所示的 float 数据十进制数值等于(-1)ign *(1.Mantissa)*2(Exponent-llllll)。

32bits

第五章:计算机是如何存储变量的,了解C++基本语言特性变量和类型

64bits

第五章:计算机是如何存储变量的,了解C++基本语言特性变量和类型

  浮点型格式说明:

  ●浮点数计算时,sign、Mantissa 和 Exponent 必须为二进制形式。

  ●对于指数部分,由于指数可正可负,对于float 类型8 位的指数位能表示的指数范围就应该为:-127~128。为了保证指数位为正数,所以指数部分的存储采用移位存储,存储的数据为元数据+127。对于 double 类型11 位的指数位能表示的指数范围就应该为:-1023~1024。为了保证指数位为正数,所以指数部分的存储采用移位存储,存储的数据为元数据+1023。

  举例说明:

  (1)8.25f的存储形式:首先将 8.25 进行二进制科学计数表示为1.0001*2b。按照上面单精度浮点数存储方式,符号位为0,表示正数;指数位为10000010B =11B+1111111B;尾数为0001 。所以8.25f在内存中的存储形式为01000001000010000000000000000000B。

  (2)120.5double 类型的存储形式:首先将120.5 进行二进制科学计数表示为1.1101101*2110b。按照上面双精度浮点数存储方式,符号位为 0,表示正数;指数位为100 0000 0101B=110B+1111111111B;尾数为 1101101。所以120.5在内存中的存储形式为0100000001011101101000000000000000000000000000000000000000000000。

  最后再介绍一些编程中经常遇到的陷阱,主要包括截断、类型转换等。截断是C++和 C变量赋值最容易出现的陷阱。截断往往隐含着赋值越界的错误,这种错误会产生什么后果取决于所使用的机器。比较典型的情况是数据越界而变成很大的负数。如果实现代码:

  char cValue --128;
  printf("cValue -%d",cValue);

  这段代码的本意应该是输出“cValue =128”,但实际上输出的却是“cValue =-128”,这就是C++语言具有的数据截断陷阱。产生这种现象的主要原因是128初始化cValue时,cValue在内存中的对应数据为10000000B(对应十进制128)。由于 10000000B为补码形式,转换成原码即是-128。

  除了截断陷阱以外,其他经常碰到的陷阱还有强制类型转换,如把一个int 型变量转换为一个char 变量会伴随着数据的丢失。

  假设定义一个int 型变量 iValue = 0x2345;,同时又定义了一个char 变量cValue 并初始化cValue=(char)iValue;,最后 cValue 的值会是多少是无法确定的。cValue 的值与字节序有关系,小端字节序下cValue 等于 0x45,大端字节序下cValue 等于 0x23。所以在实际编程过程中,应尽量避免非提升强制转换。因为非提升强制转换一般会伴随着数据精度的损失,严重情况下会出现模棱两可的现象。

  请谨记

  ●变量在不同语境下,其分配内存区域是不同的。静态变量和全局变量一般分布在全局/静态存储区,函数的参数和变量一般分配在栈中,new 和malloc 申请的数据一般分配在堆中。

  ●变量在定义和初始化时,一定要注意其取值范围,以防出现数据截断异常现象。同样,数据在使用过程中应禁止降级强制转换,这种转换一般会降低数据的精度,严重时会出现模棱两可的问题。

下一章讲解:《确保每个对象在使用前已被初始化》

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

常见问题

  • 如何安装和激活?

    每款软件会附带有安装教程,您打开安装包一目了然

  • 程序是否已损坏?文件损坏?还是其他错误?

    有错误问题,请您参考:https://www.xxx.com/error

  • 如何更新?正式激活后会发生什么情况?

    除非安装说明中另有说明,否则官方更新可能会导致无法激活。 要从本网站更新软件,您需要在此处下载此软件的新版本(如果可用),并将其安装在计算机上安装的版本之上(替换)。在这种情况下,您将保存此软件的激活和设置。

  • 如何下载?链接不起作用?

    我们使用百度网盘,132云盘和微软网盘,除了百度网盘,其他两款不限速,如果链接失效,请您联系客服处理

  • 已发布更新。我什么时候升级我的版本?

    所有软件如有更新,我们第一时间推送,视自己情况更新使用

  • 如何更改语言?

    打开“系统偏好设置”->“通用>语言和地区”->应用程序-“+”。 选择应用和语言。此方法适用于大多数应用程序。 Adobe 产品中的语言通常是在产品本身的安装阶段选择的。 游戏中的语言通常会在游戏本身的设置中发生变化。

  • 如何删除软件?

    有很多选择。最简单的方法是使用特殊的实用程序来卸载应用程序,例如App Cleaner Uninstaller 要删除 Adobe 产品,请使用 Creative Cloud Cleaner Tool

  • 需要远程帮助吗?

    网站已开通永久会员的可享受免费远程,如果非永久会员,远程安装另外收费

给TA打赏
共{{data.count}}人
人已打赏
技术教程

第四章:C++比C加了什么,了解C++程序的基本构成,快速入门指南

2024-2-13 13:01:08

技术教程

第六章:确保每个对象在使用前已被初始化,了解C++基本语言特性变量和类型

2024-2-15 10:23:00

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧