数据基本类型[C++]

C++内置的基本类型只有整数和浮点数两种。

  • 符号整型:signed char,short,int, long,long long。
  • 无符号整型:unsigned char, unsigned short,unsigned int, unsigned long, unsigned long long。
  • 整型:bool,char,wchar_t,符号整型,无符号整型,char16_t,char32_t。
  • 浮点型:float,double,long double。
  • 算数类型:整数和浮点型。

1 整数

整数就是没有小数部分的数字。计算机不能用有限的内存来表示所有的整数。

1.1 整型

C++提供好几种整型,使用不同的内存量(宽度)来存储整数。C++基本整型按照宽度递增的顺序排列依次有:

  • char
  • short(short int的简称,程序设计者几乎不会使用比较长的形式)
  • int
  • long(long int的简称)
  • long long (C++11新增)

以上的几种类型都有符号版本和无符号版本(不能表示负值),除char外都默认为有符号。仅当数值不会为负时,才应使用无符号类型。要创建无符号版本的基本整型,只需用unsigned关键字修改声明即可:

  • unsigned char(与char不一样,有符号char在类型转换时按最高位扩展;unsigned char按零扩展)
  • unsigned short
  • unsigned int(也可以用缩写unsigned)
  • unsigned long
  • unsigned long long

注意,有符号版本和无符号版本的上溢和下溢界限不一样。

C++提供了灵活的标准确保了各种基本整型的最小长度(借鉴C):

  • short至少16位;
  • int至少与short一样长;
  • long至少32位,且至少和int一样长;
  • long long至少64位,且至少和long一样长。

也就是说,int的长度有多种选择,可以是16位、24位、32位甚至是64位。32位和64位编译器对应的具体数据范围和边界值可以参考:数据范围和边界[C++]。

  • 可以使用 “sizeof(类型名或变量名)”或 “sizeof 变量名”这一运算符返回类型或变量的长度,单位为字节。
  • 字节的含义依赖于系统实现,不同系统、不同字符集对字节的定义不同:ASCII字节为8位,Unicode为16位大字符集。
  • 可以用术语八位组(octet)表示8位字节。
  • 头文件climits(老式:limits.h)包含了关于整型限制的信息,定义了各种限制符号的名称:INT_MAX、CHAR_BIT等。

C++提供很多整型,应该选择哪种呢?

  • int通常被设置为对目标计算机而言最为“自然”的长度,自然长度就是计算机处理起来效率最高的长度。如果没有非常有说服力的理由来选择其他类型,则应使用int。
  • 如果变量表示的值不可能为负,则可以使用无符号类型,这样变量可以表示更大的值。
  • 如果知道变量可以表示的整数值大于16位整数的最大可能值,则使用long。即使系统上int位32位及以上,也应这么做。如此一来,将程序移植到16位系统时就不会突然无法正常工作。如果要存储的值超过20亿,可使用long long。
  • 如果short比int小,则使用short可以减少内存。通常仅当有大型整型数组时,才有必要使用short。如果节省内存很重要,则应使用short而非int,即使两者长度一样。此时若将程序从16位系统移到32位系统,则用于int数组的内存量会加倍,而short数组不受影响。
  • 如果只需要一个字节,可使用char。

1.2 整型常量(字面值)

C++和C一样,能够以三种不同的计数方式书写整数。C++使用常量的前一(两)为来标识其基数。

  • 基数为10,常量的第一位为1~9。
  • 基数为8,常量的第一位为0,第二位为1~7。
  • 基数为16,常量的前两位为0x或0X,并用a~f或A~F补齐十六进制位。

这些表示方法仅仅是为了表达上方便,数值最终都将以二进制补码的形式存储在计算机中。

C++的头文件iostream和标准名称空间std提供数值输出格式控制符:

  • dec:十进制,一般未修改前默认为十进制。
  • hex:十六进制
  • oct:八进制
#include
using namespace std;

int main() {
    int a = 42;
    int b = 42;
    int c = 42;
    
    cout << "a = " << a << "decimal for 42" << endl;
    cout << "b = " << hex << b << "hexadecimal for 42" << endl;
    cout << "c = " << oct << c << "octal for 42" << endl;
    return 0;
}

程序声明将特定的整型变量的类型告诉了C++编译器,但编译器如确定常量类型?

  • 除非有理由存储为其它类型(如使用后缀,或者值太大而不能存储为int),否则将整型常量存储为int。
  • 可以用放在数字常量后面的字母作为后缀来表示类型。如,l或L表示long,u或U表示unsigned int,ul、LU或UL表示unsigned long,ll或LL表示long long,ull、Ull、uLL或ULL表示unsigned long long(大小写均可,顺序任意)。
  • 对于不带后缀的十进制整数,将使用int、long和long long中能够存储该数的最小类型。对于不带后缀的十六进制或八进制整数,将使用int、unsigned int、unsigned long、long long和unsigned long long中能够存储该数的最小类型。
  • 十六进制常用来表示内存地址,而内存地址时没有符号的,因此unsigned int比long更适合用来表示16位的地址。

1.3 char类型

char类型是一种整型,专为存储字符而设计,能够表示目标计算机系统所有基本符号——字母、数字、标点等。实际上很多系统支持的字符都不超过128个,故用一个字节就能表示所有符号。虽然char常用于处理字符,但也可将它用作比short更小的整型。

#include
int main() {
    using namespace std;
    char ch = 'M';
    int i = ch;
    cout << "The ASCII code for " << ch << "is " << i << endl;

    cout << "Add one to the character code:" << endl;
    ch = ch + 1;
    i = ch;
    cout << "The ASCII code for " << ch << "is " << i << endl;

    cout << "Displaying char ch using cout.put(ch):";
    cout.put(ch);
    cout.put('!');
    cout << endl << "Done" << endl;
    return 0;
}

char类型变量的输入和显示可借助iostream的智能对象:

  • 值得类型将引导cout选择如何显示对象。
  • C++将字符表示为整数,使得操纵字符很容易,不必使用笨重的转换函数。
  • 即使通过键盘输入数字给字符变量,也会被cin视为字符,即输入5会被读取为字符‘5’,并存储为对应的字符编码。
  • 成员函数cout.put()可用来显示字符变量和字符常量。(C++ Release2.0之前遗留)
char ch;
cin >> ch; //输入5并回车,代码将读取字符“5”,其存储的ASCII编码为53

int n;
cin >> n;  //输入5并回车,代码将读取数值5

cout << '$'; //C++ Release2.0之前会打印'$'对应的ASCII码
cout.put('$'); //C++ Release2.0之前可以打印字符'$'
//cout在C++ Release2.0之后可以正确地处理字符常量

C++书写字符常量(char字面值)的方法很多:

  • 对于常规字符(如字母、数字和标点),最简单的方法是将字符用单引号括起。这种表示法代表的是字符的数值编码。
  • 有些字符不能直接通过键盘输入到程序中去,如按回车不能使一个字符串包含换行符,而C++提供转义序列来表示它们。
  • 现代系统并非支持所有的转义序列,如有些系统会对输入的振铃字符表示沉默。有些基于ANSI C之前的编译器的C++系统就不能识别\a。对于使用ASCII字符集的系统,可以用\007代替\a。
  • 换行符'\n'(或"\n")可代替endl,用于在输出中重起一行。可以将换行符嵌入到字符串中,这比使用endl更方便。显示数字时使用endl比换行符更容易输入,但显示字符串是末尾加换行符输入量会少一些。
  • 可以基于字符的八进制和十六进制编码来使用转移序列。数字表示与特定的编码方式相关(如ASCII码),而符号表示适用于任何编码方式,其可读性也更强。
  • 有些系统的\b未必是退格,也可能是显示一个小矩形,或者在退格时删除。

ASCII系统对应的字符编码情况:

Ctrl + Z:编码为26,即032或0x1a,其转移序列为\032或\0x1a

A~Z:65~90      a~z:97~122       0~9:48~57      空格字符:32

换行符:10,\n      退格:8,\b或\0x8       回车:13,\r      振铃:7,\a或\007

水平制表符:9,\t         垂直制表符:11,\v          反斜杠:92,\\

问号:63,\?                 单引号:39,\'                  双引号:34,\"

//换行
cout << endl;
cout << '\n';
cout << "\n";

C++实现支持一个基本的源字符集,可用来编写源代码。还有一个基本的执行字符集,包括在程序执行期间可处理的字符。C++标准还允许实现提供扩展源字符集和扩展执行字符集。另外,那些被作为字母的额外字符也可以用于标识符名称中。

  • C++有一种表示这种特殊字符的机制,它独立任何特定的键盘,使用的是通用字符名(类似于转义序列),以\u或\U打头。\u后面是8个十六进制位,\U后面是16个十六进制位,这些位表示的是字符的ISO 10646码点。
  • Unicode提供表示各种字符集的解决方案,为大量字符和符号提供标准数值编码,并根据类型将它们分组。
  • ASCII是Unicode的子集。
  • 实现的扩展字符集可能允许从键盘输入某些特殊字符。
int k\u00F6rper; \\从变量声明角度来说,这样做没多大意义
cout << "Let them eat g\u00E2teau.\n";

与int不同的是,char在默认情况下既不是没有符号,也不是有符号。

  • 可以显式地设置类型为signed char或unsigned char。
  • 如果将char用作数值类型,有无符号表示的数值范围不同。不同系统对char的默认支持范围也不同。
  • 如果用char变量来存储标准ASCII字符,char有没有符号都没有关系。

有时程序需要处理的字符集可能无法用一个8位的字节表示,C++的处理方式有两种:

  • 如果大型字符集是系统实现的基本字符集,则编译器厂商可以将char定义为一个16位的字节或更长的字节。
  • 如果实现同时支持一个小型字符集和一个较大的扩展字符集,8位char可以表示基本字符集,wchar_t可以表示扩展字符集。

wchar_t是一种整数类型,有足够的空间,可以表示系统使用的最大扩展字符集。

  • 这种类型与另一种整型(底层(underlying)类型)的长度和符号属性相同。
  • 对底层类型的选择取决于系统实现,它有可能在一个系统中是unsigned short,而在另一个系统中是int。
  • cin和cout将输入和输出看作是char流,不适于处理wchar_t类型。
  • iostream文件的新版本中提供wcin和wcout,可用于处理wchar_t流。
  • 可以通过加上前缀L来指示宽字符常量和宽字符串。

仅使用Unicode码点并不够,类型wchar_t也不能满足需求,进行字符串编码时如果有特定长度和符号特征的类型将很有帮助。

  • C++11新增了类型char16_t和char32_t,都是无符号的,前者长16位,后者长32位。
  • C++11使用前缀u表示char16_t字符常量和字符串常量,使用前缀U表示char32_t字符常量和字符串常量。
  • 类型char16_t与\u打头的通用字符名相匹配,类型char32_t与\U打头的通用字符名相匹配。
  • char16_t和char32_t也都有底层类型,即一种内置的类型,只是底层类型随系统实现。

1.4 bool类型

ANSI/ISO C++标准添加了一种名叫bool的新类型(对C++而言),即逻辑的数学表示。

  • 过去C++和C一样没有布尔类型。
  • 布尔变量的值可以是true或false。
  • C++将非零值解释为true,零解释为false。
  • 字面值true或false都可以通过提升转换为int类型,true转换为1,false转换为零。
  • 任何数字值或指针值都可以被隐式转换为bool值,任何非零值都被转换为true。
int a = true; //1
int b = false; //0

bool start = -100; //true
bool end = 0; //false

2 浮点数

浮点数能够表示小数值、非常大和非常小的值,即带小数的数字。计算机将这样的数字分两部分存储:值和缩放因子。

2.1 书写浮点数

C++有两种书写浮点数的方式。

  • 常用的标准小数点表示法:12.34,0.0023,8.0等。即使小数部分为零,小数点也将确保该数字以浮点格式表示。
  • E表示法:2.52e+8,8.33E-4,7E5,-18.32e13,2.e8,.5e4等。该法适合非常大和非常小的数。

注意:

  • E表示法确保数字以浮点格式存储,即使没有小数点。
  • 既可以使用E亦可以使用e,指数可以是帧数也可以是负数。
  • 数字中不能有空格,比如7.2 E6就是非法的。

2.2 浮点类型

和ANSI C一样,C++有3种浮点类型:

  • float
  • double
  • long double

这些类型是按它们可以表示的有效位数和允许的指数最小范围来描述的。

  • 有效位是数字中有意义的位。
  • 有效位数不依赖于小数点的位置。
  • float有效位至少32位,double至少48位且不少于float,long double至少和double一样多。
  • 三种类型有效位可以一样多,通常float 32位,double 64位,long double位80、96或128位。
  • 三种类型的指数范围至少是-37~37。
  • 可从头文件cfloat或 float.h中找到系统限制。有些C++实现未添加cfloat,有些基于ANSI C之前的编译器的C++没有float.h。
  • 在对应类型的有效位数范围之外操作数值,对数值没有影响。
#include
using namespace std;

int main() {
    float a = 2.34E+22f; //#define FLT_DIG 6
    float b = a + 1.0f; //不支持f后缀的可用:float b = a + (float)1.0;

    cout << "a = " << a << endl;
    cout << "b -a = " << b-a << endl;
    return 0;
}

//输出结果为:
// a = 2.34e+22
// b - a = 0

2.3 浮点常量

程序中书写浮点常量时,默认为double类型。

  • 如果希望常量位float类型,应使用f或F后缀。有些基于ANSI C前的编译器的老式C++不支持后缀f,可用(float)强制转换。
  • 对于long double类型,可使用l或L后缀。(由于l看起来像数字1,因此L是更好地选择。)
1.234f  //float常量
2.45E20F //float常量
2.354E25 //double常量
2.2L //long double常量

2.4 浮点数的优缺点

浮点数相比于整数的优点:

  • 浮点数可以表示整数之间的值。
  • 由于有缩放因子,浮点数可以表示的范围大得多。

然而,浮点运算的速度通常比整数运算慢,且精度将降低。

你可能感兴趣的:(C++)