3.什么是数据类型?
对初学者来说,理解数据类型可能是一个难题。我们已经知道int代表整数,char代表字符,float代表浮点数,但是这些数据类型在内存中是如何存储的?数据类型对于计算机有什么意义?我们还不是十分清楚。
有些人的观点是,理解数据类型是一个循序渐进的过程,一开始的不理解并不会阻碍初学者打好编程基础,随着编写的代码越来越多,再来学习内存的知识,会更加容易。我也十分认同这种观点,数据类型及内存方面的知识不是一下可以吃透的,但如果读者仍充满了好奇,坚持要理解数据类型,阅读本节也是一个不错的选择。
定义
在开始进入本节的学习之前,让我们先来看一下数据类型的定义,尽管定义可能有些枯燥:数据类型在数据结构中的定义是一个值的集合以及定义在这个值集上的一组操作。变量是用来存储值的所在处,它们有名字和数据类型。变量的数据类型决定了如何将代表这些值的位存储到计算机的内存中。在声明变量时也可指定它的数据类型。所有变量都具有数据类型,以决定能够存储哪种数据。
位、字节、字
从数据类型的定义可以看出,数据类型解决的是变量存储的问题。要理解数据类型,首先需要了解计算机是如何存储数据的。我们都知道,计算机的世界是二进制的,仅仅用0和1就构建了所有的表达,计算机用来存储0或者1的单位是位(bit),8个位组成一个字节(byte),位和字节的定义如图3.1所示。
图3.1 位和字节
位:表示二进制位。位是计算机内部数据存储的最小单位,一个二进制位只可以表示0和1两种状态;两个二进制位可以表示00、01、10、11四种状态;三个二进制位可以表示八种状态。
字节:计算机中数据存储的基本单位。一个字节由8个二进制位构成。八位二进制数最小为00000000,最大为11111111,可以表示256种状态;通常一个字节可以存入一个ASCII码,两个字节可以存放一个汉字国标码。
字:在计算机中,一个固定长度的位组作为一个整体来处理或运算,称为一个计算机字,简称字。字通常分为若干个字节,其长度用位数表示,常见的有16位、32位、64位等。字长越长,计算机一次处理的信息位越多、精度越高,字长是衡量计算机性能的一个重要指标。
综上所述,计算机通过对每一位赋予不同的值(0或1)来存储不同的信息,一个字节可以表示256种状态。以ASCII码为例,它一共定义了128个字符的编码,因此只需要占用一个字节的后7位就可以表示所有这128种不同的状态,最前面的1位就统一规定为0。
理解数据类型
示例代码3.1
为了理解数据类型,我们首先来阅读示例代码3.1。在该段代码中,首先定义了一个char类型的数组s,该数组共有两个元素,分别是'A'和'B'。C++中,char类型占一个字节,其中,数组第一个元素'A'的ASCII码值为65(对应的二进制表示为01000001),数组第二个元素'B'的ASCII码值为66(对应的二进制表示为01000010),数组的元素在内存中连续存放,因此数组s在内存中的存储方式如图3.2所示。
图3.2 数组s在内存中的存储方式
现在我们知道,内存中存在连续的两个字节存放着数组s,这两个字节的内容是01000001和01000010。回到示例代码3.1,在第6行,我们定义了一个短整型指针,指针的值是数组s的地址,也就是数组s第一个元素的地址,在笔者的编译环境中,short类型占两个字节。读者也许还不理解指针是什么意思,接着看示例代码3.1第7行,我们将指针所指的内容打印到屏幕。结合看第6行和第7行代码,我们做的其实是将数组s所占用的两个字节的内容看成是存放着一个short类型的值,然后将这个值输出到屏幕,由于笔者运行代码的CPU采用小端序存储,即低地址存放低位值,高地址存放高位值,因此输出的short类型的值为16961(16961=66×256+65)。关于大端序、小端序的知识,读者可以参考本节最后部分。
通过这个例子,读者应该已经发现数据类型的作用了。对于内存中存放的两个字节的内容,计算机可以将其理解为两个char类型的值,也可以将其理解为一个short类型的值,我们需要告诉计算机如何去解析内存中存放的内容,如何去告诉呢?这正是数据类型要完成的任务。当我们定义了一个char类型的变量时,计算机在分配内存给变量的时候同时记住了这片内存中存放的是怎样一类数据。再举一个例子,对于一个字节的内容01000001,计算机可以将其理解为一个byte类型的值,即65,也可以将其理解为一个char类型的值,即'A'。
C++中的基本数据类型
在理解了数据类型之后,我们先看一下C++中的基本数据类型。C++中定义了一组表示整数、浮点数、单个字符和布尔值的算术类型,算术类型的存储空间依机器而定。这里的存储空间是指用来表示该类型的二进制位数。C++标准规定了每个算术类型的最小存储空间,但它并不阻止编译器使用更大的存储空间。因为位数不同,这些类型所能表示的最大值和最小值也因机器的不同而有所不同。表3.1列举了C++中各种基本数据类型,包括占用的空间大小(C++标准规定的最小存储空间)以及取值范围。
表3.1 C++中的各种基本数据类型
Java中的基本数据类型
Java的基本数据类型区别于C++的基本数据类型的地方是,Java中的基本数据类型所占的存储空间是固定的,不会因为机器的不同而不同,这是因为Java程序运行在JVM(Java Virtual Machine)之上,从而使得运行环境与平台无关。
Java基本类型共有8种,可以分为三类,字符类型char,布尔类型boolean以及数值类型byte、short、int、long、float、double。Java中的数值类型不存在无符号的,且取值范围是固定的。实际上,Java中还存在另外一种基本类型void,不过我们无法直接对它们进行操作。表3.2列举了Java中的8种基本数据类型,包括占用的空间大小以及取值范围。
大端序与小端序
字节序又称端序、尾序。在计算机科学领域中,字节序是指存放多字节数据的字节的顺序。如果数据都是单字节的,那就无所谓数据内部的字节顺序了;但是对于多字节数据,比如int、double等,就要考虑数据内部字节的顺序了。常见字节序包括以下两种:
(1)大端序:数据的高位字节存放在低地址端,低位字节存放在高地址端。
(2)小端序:数据的高位字节存放在高地址端,低位字节存放在低地址端。
为了直观地理解字节序,我们以一个long类型的数据为例,查看该数据在不同字节序中存储的方式。现在定义一个long类型数据0x12345678(十六进制表示,关于进制的知识读者可以参考第4节),该数据在内存中一共占用了4字节。
在大端序存储数据的机器中,该数据从内存低地址到内存高地址的四个字节分别存放的值为0x12、0x34、0x56、0x78,如表3.3所示。而在小端序存储数据的机器中,该数据从内存低地址到内存高地址的4字节分别存放的值为0x78、0x56、0x34、0x12,如表3.4所示。
表3.3 大端序数据存储方式
表3.4 小端序数据存储方式