大多数编程语言通过两种方式来进一步补充其基本特征:一是赋予程序员自定义数据类型的权利,从而实现对语言的扩展;二是将一些有用的功能封装成库函数提供给程序员。
与大多数编程语言一样,C++的对象类型决定了能对该对象进行的操作,一条表达式是否合法依赖于其中参与运算的对象的类型。一些语言,如Smalltalk和Python等,在程序运行时检查数据类型;与之相反,C++是一种静态数据类型语言,它的类型检查发生在编译时。因此,编译器必须知道程序中每一个变量对应的数据类型。
1.基本内置类型
C++定义了一套包括算术类型(arithmetic type)和空类型(void)在内的基本数据类型。其中算术类型包含了字符、整数型、布尔值和浮点数。空类型不对应具体的值,仅用于一些特殊的场合,例如最常见的是,当函数不返回任何值时使用空类型范围返回值。
2.算术类型
算术类型分两类:整型(integer type,包括字符和布尔类型在内)和浮点型。
类型 | 含义 | 最小尺寸 |
bool | 布尔类型 | 未定义 |
char | 字符 | 8位 |
wchar_t | 宽字符 | 16位 |
char16_t | Unicode字符 | 16位 |
char32_t | Unicode字符 | 32位 |
short | 短整型 | 16位 |
int | 整型 | 16位 |
long | 长整型 | 32位 |
long long | 长整型 | 64位 |
float | 单精度浮点数 | 6位有效数字 |
double | 双精度浮点数 | 10位有效数字 |
long double | 扩展精度浮点数 | 10位有效数字 |
32位和64位C语言内置数据类型,如下表所示:
type | LP32 | ILP32 | LP64 | LLP64 | ILP64 |
---|---|---|---|---|---|
char | 8 | 8 | 8 | 8 | 8 |
short | 16 | 16 | 16 | 16 | 16 |
int | 16 | 32 | 32 | 32 | 64 |
long | 32 | 32 | 64 | 32 | 64 |
long long | 64 | 64 | 64 | 64 | 64 |
pointer | 32 | 32 | 64 | 64 | 64 |
float | 32 | 32 | 32 | 32 | 32 |
double | 64 | 64 | 64 | 64 | 64 |
上表中第一行的大写字母和数字含义如下:
I表示:int类型
L表示:long类型
P表示:pointer指针类型
32表示:32位系统
64表示:64位系统
从实现角度来说,64位Linux采用的是LP64模型,这意味着Long, Pointer都是8字节。32位Linux采用的是ILP32模型,也就是Int Long Pointer均为4字节。Windows下32位是ILP32,64位是LLP64。
#include <iostream>
int main()
{
std::cout << "sizeof(bool) = " << sizeof(bool) << std::endl;
std::cout << "sizeof(char) = " << sizeof(char) << std::endl;
std::cout << "sizeof(short) = " << sizeof(short) << std::endl;
std::cout << "sizeof(int) = " << sizeof(int) << std::endl;
std::cout << "sizeof(long) = " << sizeof(long) << std::endl;
std::cout << "sizeof(long long) = " << sizeof(long long) << std::endl;
std::cout << "sizeof(float) = " << sizeof(float) << std::endl;
std::cout << "sizeof(double) = " << sizeof(double) << std::endl;
std::cout << "sizeof(long double) = " << sizeof(long double) << std::endl;
return 0;
}
布尔类型(bool)的取值是真(true)和假(false)。
C++提供了几种字符类型,其中大多数支持国际化。基本的字符类型是char,一个char的空间应确保可以存放机器基本字符集中任意字符对应的数字值。也就是说,一个char的大小和机器字节一样。
其他字符类型用于扩展字符集,如wchar_t、char16_t、char32_t。wchar_t类型用于确保可以存放机器最大扩展字符集中的任意一个字符,类型char16_t和char32_t则为Unicode字符集服务(Unicode是用于表示所有自然语言中字符的标准)。
除了字符和布尔类型之外,其他整型用于表示(可能)不同尺寸的整数。C++语言规定一个int至少和一个short一样大,一个long至少和一个int一样大,一个long long至少和一个long一样大。其中,数据类型long long是在C++11中新定义的。
浮点型可表示单精度、双精度和扩展精度值。C++标准指定了一个浮点数有效位数的最小值,然后大多数编译器都实现了更高的精度。通常,一个float以1个字(32比特)来表示,double以2个字(64比特)来表示,long double以3或4个字(96或128比特)来表示。一般来说,类型float和double分别有7和16个有效位;类型long double则常常被用于有特殊浮点需要的硬件,它的具体实现不同,精度也各不相同。
注意:计算机以比特序列存储数据,每个比特非0即1。大多数计算机以2的整数次幂个比特位作为块来处理内存,可寻址的最小内存块称为“字节(byte)”,存储的基本单元称为“字(word)”,它通常由几个字节组成。在C++语言中,一个字节要至少能容纳机器基本字符集中的字符。大多数机器的字节由8比特构成,字则由32或64比特构成,也就是4或8字节。
浮点数的二进制表示遵循IEEE754二进位浮点算术标准。指数
float
1bit(符号位) | 8bits(指数位) | 23bits(尾数位) |
double
1bit(符号位) | 11bits(指数位) | 52bits(尾数位) |
float的指数位有8位,而double的指数位有11位,
于是,float的指数范围为-127~128,而double的指数范围为-1023~1024,并且指数位是按补码的形式来划分的。其中负指数决定了浮点数所能表达的绝对值最小的数;而正指数决定了浮点数所能表达的绝对值最大的数,也即决定了浮点数的取值范围。
float的范围为-2^128 ~ +2^128,也即-3.40E+38 ~ +3.40E+38;double的范围为-2^1024 ~ +2^1024,也即-1.79E+308 ~ +1.79E+308。
2.float和double的精度是由尾数的位数来决定的。浮点数在内存中是按科学计数法来存储的,其整数部分始终是一个隐含着的“1”,由于它是不变的,故不能对精度造成影响。
float:2^23 = 8388608,一共7位,这意味着最多能有7位有效数字,但绝对能保证的为6位,也即float的精度为6~7位有效数字;
double:2^52 = 4503599627370496,一共16位,同理,double的精度为15~16位。
3.带符号和无符号类型
除去布尔型和扩展的字符型之外,其他整型可以划分为带符号的(signed)和无符号的(unsigned)两种。带符号类型可以表示正数、负数和0,无符号类型仅能表示大于等于0的值。
类型int、short、long和long long都是带符号的,通过在这些类型名前添加unsigned就可以得到无符号类型,例如unsigned long。类型unsigned int可以缩写为unsigned。
与其他整型不同,字符型被分为了三种:char、signed char和unsigned char。特别需要注意的是:类型char和类型signed char并不一样。尽管字符型有三种,但是字符的表现形式只有两种:带符号和无符号的。类型char实际上会表现为上述两种形式中的一种,具体是哪种由编译器决定。
无符号类型中所有比特都用来存储值,例如,8比特的unsigned char可以表示0至255区间内的值。
C++标准并没有规定带符号类型应如何表示,但是约定了在表示范围内正值和负值的量应该平衡。因此8比特的signed char理论上应该可以表示-127至127区间内的值,大多数现代计算机将实际的表示范围定为-128至127。