数据类型
时间:2010-08-26 来源:snailshen
2.1 基本内置类型
类型是所有程序的基础。类型告诉我们数据代表什么意思以及可以在数据上执行哪些操作。
C++定义了几种基本类型:字符型、整型、浮点型,等等。该语言还提供了允许自定义数据类型的机制,标准库利用这些机制定义更复杂的类型,比如可变长字符串string、vector等,还能修改已存在的类型以形成复合类型。本章介绍内置类型,并开始介绍C++如何支持更复杂的类型。
类型确定了数据和操作在程序中的意义。就像我们在第1章看到的,语句
i=i+j;
有不同的含义,取决于i和j的类型。如果i和j都是整型,则这条语句表示一般的算术“+”运算;如果i和j都是Sales_item对象,则这条语句是将这两个对象的组成成分加起来。
C++中,类型的支持是广泛的:该语言本身定义了一组基本类型和修改已有类型的方法,还提供了一组特性允许自定义类型。本章通过介绍内置类型和如何关联类型与对象来探讨C++中的类型。本章还将介绍更改类型和建立自定义类型的方法。
2.1基本内置类型
C++定义了一组表示整数、浮点数、单个字符和布尔值的算术类型(arithmetic types),另外还定义了一种称为void的特殊类型。void类型没有对应的值,仅用在有限的情况下。通常用作无返回值的函数的返回类型。
算术类型的存储空间依机器而定。类型存储空间是指用来表示该类型的位(bit)数。C++标准保证了每个算术类型的最小存储空间,但它并不阻止编译器使用更大的存储空间。事实上,对于int类型,几乎所有的编译器使用的存储空间都比所要求的大。表2-1列出了内置算术类型和其对应的最小存储空间。
因为位数的不同,这些类型所能表示的最大(最小)值也因机器的不同而有所不同。
内置类型的机器级表示
C++的内置类型与其在计算机的存储表示紧密相关。计算机以位序列存储数据,每一位存储0或1。一段内存可能存储着
00011011011100010110010000111011……
在位这一级上,存储是没有结构和意义的。
让存储具有结构的最基本的方法是用块(chunk)处理存储。大部分计算机都使用特定位数的块处理存储,块的位数一般是2的幂,因为这使得一次处理8、16或32位变得容易。64和128位的块也变得更为普遍。虽然确切的大小因机器不同而不同,但是通常将8位的块作为一个字节,32位或4个字节作为一个“字(word)”。
大多数计算机将存储器中的每一个字节和一个叫做地址的数关联起来。假如给定一个8位字节和32位字的机器,我们可以将存储器的字表示如下:
在这个图中,字节地址表示在左边,地址后面为字节的8位。
可以用地址表示以该地址开始的任何几个不同大小的位集合。可以说地址为736424的字,也可以说地址为736426的字节。例如,可以说地址为736425的字节和地址为736427的字节不相等。
要让地址为736425的字节具有意义,必须要知道存储在该地址的值的类型。一旦知道了该地址的值的类型,就知道了表示该类型的值需要多少位和如何解释这些位。
如果知道地址为736425的字节的类型是8位无符号整数,那么就可以知道该字节表示整数112。另外,如果这个字节是ISO-Latin-1字符集中的一个字符,那它就表示小写字母q。虽然两种情况的位相同,但归属于不同类型,解释也就不同。
2.1.1整型
表示整数、字符和布尔值的算术类型都看作整型。
字符类型有两种:char和wchar_t。char类型保证了有足够的空间存储机器基本字符集中任何字符相应的数值,因此,char类型通常是单个机器字节(byte)。wchar_t类型用于扩展字符集,比如汉字和日语,这些字符集中的一些字符不能用单个char表示。
short、int和long类型都表示整型值,但具有不同大小的存储空间。一般,short类型为半个机器字长,int类型为一个机器字长,而long类型为一个或两个机器字长(在32位机器中int类型和long类型通常字长是相同的)。
bool类型表示真值true和false。可以将算术类型的任何值赋给bool对象。0值算术类型代表false,任何非0的值都代表true。
1.带符号和无符号类型
除bool类型外,整型可以是带符号的(signed)也可以是无符号的(unsigned)。顾名思义,带符号类型可以表示正数也可以表示负数(包括0),而无符号型只能表示大于或等于0的数。
整型int、short和long都默认为带符号型。要获得无符号型则必须指定该类型为unsigned,比如unsigned long。unsigned int类型可以简写为unsigned,也就是说,unsigned后不加其他类型标识符意味着是unsigned int。
和其他整数类型不同,char有三种不同的类型:plain char、unsigned char和signed char。虽然char有三种不同的类型,但只有两种表示方式。可以使用unsigned char或signed char表示char类型。使用哪种char表示方式由编译器而定。
表2-1 C++:算术类型
类型
含义
最小存储空间
bool
布尔型
NA
char
字符型
8位
wchar_t
宽字符型
16位
short
短整型
16位
int
整型
16位
续表
类型
含义
最小存储空间
long
长整型
32位
float
单精度浮点型
6位有效数
double
双精度浮点型
10位有效数
long double
扩展精度浮点型
10位有效数
2.如何表示整数值
无符号型中,所有的位都表示数值。如果在特定的机器中,定义一种类型使用8位表示,那么这种类型的unsigned型可以取值0到255。
C++标准并未定义signed类型如何用位来表示,而是由每个编译器自由决定如何表示signed类型。这些表示方式会影响signed类型的取值范围。可以确保8位的signed类型取值至少从-127到127,也有许多实现允许取值从-128到127。
最常见的表示signed整数类型的策略是用其中一个位作为符号位。符号位为1,值就为负数;符号位为0,值就为0或正数。一个signed整数取值是从-128到127。
3.对整型赋值
对象的类型决定对象的取值。这会引起一个疑问:当我们试着把一个超出其取值范围的值赋给一个指定类型的对象时,结果会怎样呢?答案取决于这种类型是signed还是unsigned。
对于unsigned类型来说,编译器必须调整越界值使其满足要求。编译器是通过取该值对unsigned类型可以取的不同值的数目求模后的值来实现的。比如8位的unsigned char,其取值范围从0到255(包括255)。如果赋给超出这个范围的值,那么编译器将会取该值对256求模后的值。例如,我们可以试着将336赋值给8位的signed char。如果试图将336存储到8位的unsigned char中,实际赋值为80,因为80是336对256求模后的值。
对于unsigned类型来说,负数总是超出其取值范围。unsigned类型的对象不可取负数,有些语言把负数赋给unsigned类型看成是非法的,但在C++中是合法的。
C++中,把负值赋给unsigned对象是完全合法的,其结果是该负数对该类型的取值个数求模后的值。所以,如果把-1赋给8位的unsigned char,那么结果是255,因为255是-1对256求模后的值。
当将超过取值范围的值赋给signed类型时,由编译器决定实际赋的值。在实际操作中,很多的编译器处理signed类型和处理unsigned类型类似。也就是说,赋值时是取该值对该类型的取值个数求模后的值。然而我们不能保证编译器都会这样处理signed类型。
2.1.2浮点类型
类型float、double和long double分别表示单精度浮点数、双精度浮点数和扩展精度浮点数。一般float类型用一个字(32位)来表示,double类型用两个字(64位)来表示,long double类型用三个或四个字(96或128位)来表示。类型的取值范围决定了浮点数含有的有效数字位数。
对于实际的程序来说,float类型精度通常是不够的——float型只能保证6位有效数字,而double型至少可以保证10位有效数字,能满足大多数计算的需要
Size
数值范围
无值型void
0 byte
无值域
布尔型bool
1 byte
true false
有符号短整型short [int] /signed short [int]
2 byte
-32768~32767
无符号短整型unsigned short [int]
2 byte
0~65535
有符号整型int /signed [int]
4 byte
-2147483648~2147483647
无符号整型unsigned [int]
4 byte
0~4294967295
有符号长整型long [int]/signed long [int]
4 byte
-2147483648~2147483647
无符号长整型unsigned long [int]
4 byte
0~4294967295
long long
8 byte
0~18446744073709552000
有符号字符型char/signed char
1 byte
-128~127
无符号字符型unsigned char
1 byte
0~255
宽字符型wchar_t (unsigned short.)
2 byte
0~65535
单精度浮点型float
4 byte
-3.4E-38~3.4E+38
双精度浮点型double
8 byte
1.7E-308~1.7E+308
long double
8 byte
说明:
(1)类型修饰符signed和unsigned用于修饰字符型和整形。 (2)类型修饰符short和long用于修饰字符型和整形。 (3)当用signed和unsigned、short和long修饰int整形时,int可省略。 (4)其中bool和wchar_t是C++特有的。 (5)除上表以外,C/C++都可以自定义枚举enum、联合union和struct结构体类型。 (6)以上sizeof通过Windows XP 32位平台测试,其中某些类型数据的字节数和数值范围由操作系统和编译平台决定。比如16位机上,sizeof(int) = 2,而32位机上sizeof(int) = 4;32位机上sizeof(long) = 4,而64位机上sizeof(long) = 8。除此之外,注意64位机上的pointer占8byte。 (7)void的字面意思是“无类型”,不能用来定义变量。void真正发挥的作用在于:<1> 对函数返回和函数参数的限定,例如自定义既不带参数也无返回值的函数void MyFunc(void);<2>定义无类型通用指针void *,指向任何类型的数据。 (8)标准C++库及STL还提供了通用数据结构:字符串类string;向量类模板vector;双端队列类模板deque;链表类模板list;容器适配器堆栈类stack(实现先进后出的操作);容器适配器队列类queue(实现先进先出的操作);集合类set;多重集合类multiset;映射类map;多重映射类multimap;位集合bitset;迭代器iterator (类似指针的功能,对容器的内容进行访问)。 (9)在标准c++中,int的定义长度要依靠你的机器的字长,也就是说,如果你的机器是32位的,int的长度为32位,如果你的机器是64位的,那么int的标准长度就是64位,而vc中__int64是为在32机位机器长实现64位长度的整形数。 (10)关于32位平台下的int和long long从字面上看,应该是64位才更合理,把long当成32位实在是一个历史的包袱。像C#那样新起炉灶的程序语言,由于没有需要支持老代码的问题,就把long当作64位来处理了。 在32位平台下,long是相对short而言,long(short)类型是long(short) int类型的简称,sizeof(long) = sizeof(int) = 4。int和long的范围虽然一样,但输入输出格式不同,printf int的格式为%d,而printf long的格式为%ld。 考虑到程序的可移植性,还是要将他们区分开来。但当要求的数值范围为4byte时,建议使用int类型,因为第一版的C语言只有一种类型,那就是int。 (11)在Win32 API及MFC中为了使类型名称在语意上更明了,对以上基本类型进行了大量的typedef。例如WINDEF.H中的BYTE,WORD,DWORD。 (12)计算机内部内存的基本单位是1byte(8个电子开关)!