- 内置的C++类型分为两组:简单类型和复合类型,本章介绍基本类型:整数和浮点数。
3.1 简单变量
3.1.1 变量名
- 变量名命令规则:
1、在名称中只能使用字母字符、数字和下划线
2、名称的第一个字符不能是数字
3、区分大小写字符
4、不能将C++关键字用于变量名称
5、以两个下划线打头或下划线和大写字母打头的名称被保留给实现(编译器及其使用的资源)使用,一个下划线开头的名称被保留给实现,用作全局标识符
6、C++对于名称长度没有限制,但是平台会有限制
3.1.2 整型
- C++整型分别为:char、short、int、long、和C++11新增的long long。
3.1.3 整型short、int、long和long long
- C++中对类型的长度采取灵活的实现,确保了最小的长度:
1、short至少16位
2、int至少和short一样
3、long至少32位,且至少与int一样长
4、long long至少64位,且至少与long一样长
- Ubuntu 20.0.4 64位显示
#include <iostream>
#include <climits>
using namespace std;
int main() {
int a = INT_MAX;
short b = SHRT_MAX;
long c = LONG_MAX;
long long d = LLONG_MAX;
cout << "int size is " << sizeof a << endl;
cout << "short size is " << sizeof b << endl;
cout << "long size is " << sizeof c << endl;
cout << "long long size is " << sizeof d << endl;
cout << endl;
cout << "Maximum values:" << endl;
cout << "int: " << a << endl;
cout << "short: " << b << endl;
cout << "long: " << c << endl;
cout << "long long: " << d << endl;
return 0;
}
输出
int size is 4
short size is 2
long size is 8
long long size is 8
Maximum values:
int: 2147483647
short: 32767
long: 9223372036854775807
long long: 9223372036854775807
- 可对类型名或者变量名使用sizeof,当对类型名使用时,需要加括号,如sizeof (int) ,而对变量名时,括号是可选的。
3.1.4 无符号整型
- 上节中的4种整型都有一种无符号的变体,优点是可以增大变量能够存储的最大值。
- 无符号整型和有符号整型都存在整数溢出行为,无符号数超过最大值后会从0重新开始,有符号数则是从最小值重新开始。
3.1.5 选择整型类型
- 通常,int被设置为对目标计算机来说处理效率最高的长度。如果没有其他理由,一般使用int
- 如果为非负整数,则选择无符号类型
- 如果整数数值大于16位,则应选择long,即使系统int是32位的,这样将程序移植到16系统上时,就不会无法工作
- 通常仅当有大型整型数组时,才有必要使用short,即使short和int一样位数,因为从16位机移植到32位机,占用内存会翻倍,而short不会。
3.1.6 整型字面值
- 对于C++整型字面值,使用前一(两)位来标识数字常量的基数,第一位为1~9,则基数为10;第一位为0,则基数为8;前两位为0x或0X则基数为16。
#include <iostream>
using namespace std;
int main() {
int a = 42;
int b = 0x42;
int c = 042;
cout << a << endl;
cout << b << endl;
cout << c << endl;
return 0;
}
输出
42
66
34
- cout提供了三种控制符,用于输出十进制、十六机制和八进制的数
#include <iostream>
using namespace std;
int main() {
int a = 42;
int b = 42;
int c = 42;
cout << dec;
cout << a << endl;
cout << hex;
cout << b << endl;
cout << oct;
cout << c << endl;
return 0;
}
输出
42
2a
52
3.1.7 C++如何确定常量的类型
- 除非有理由储存为其他类型,否则都是int类型。理由有使用特殊的后缀来表示特定的类型,或者值太大,不能存储为int。
- 后缀:数字后加l或者L表示long常量,u或者U表示unsigned int类型,组合起来uL表示unsigned long类型,以此类推。
- 数据长度则根据具体系统支持的数据的最大长度来。
3.1.8 char类型:字符和小整数
- char类型是专为存储字符设计的,是整型类型,可以表示比short更小的数,占一个字节。
#include <iostream>
using namespace std;
int main() {
char a = 77;
cout << a << endl;
return 0;
}
输出
M
- char存储的是字符的编码值,打印出M是因为cin和cout都能够处理字符。C++实现使用的编码是主机系统的编码。一般编码都包含ASCII编码,C++支持的wchar_t的宽字符类型能够存储更多的值,如Unicode编码。
#include <iostream>
using namespace std;
int main() {
char a = 77;
cout << "a is ";
cout.put(a);
return 0;
}
输出
a is M
- cout的put函数提供了另一种显示字符的方法,可以替代<<运算符。
- char字面值,char字面值使得在不同的编码中表示同一个字符,但其存储到计算机中的编码值可能不同。
- 有些无法通过键盘输入的字符则需要转义,C++有专门的转义序列编码。
- 与int不同的是,char在默认情况下既不是有符号的,也不是无符号的,是否有符号由C++实现决定,可以通过显示的将类型设置为signed char或unsigned char。
- wchar_t可以扩展字符集,cin和cout对应char的字符流,对于wchar_t,也有相应的工具,是wcin和wcout。
- C++11新增了char16_t和char32_t,前者是16位无符号类型的,后者是32位无符号类型的,可以使用u和U标识这两种类型
char16_t ch1 = u'q';
char32_t ch2 = U'/U0000222B';
- 与wchar_t一样,char16_t和char32_t也都有底层类型——一种内置的整型,但底层类型可能随系统而变。
3.1.9 bool类型
- bool值表示true或者false,C++中将非零值表示我true,零表示为false。
- 任何数字或者指针都可以被隐式转换成bool值。
3.2 const限定符
- 字符串常量可以使用define的预处理定义,也可以使用const修饰符定义字符串常量。
3.3 浮点数
- 有小数类型的称为浮点数,对于浮点数,计算机将这样的值分为两部分存储,一部分表示值,另一个部分表示对值进行放大或缩小。由于放大缩小都是移动点的位置,所以称为浮点数,点的移动,缩放倍数是2的倍数。
3.3.1 书写浮点数
- 浮点数的书写可以采用最常见的小数形式,也可以采用科学表示法。
3.3.2 浮点类型
- C++有三种浮点类型:float、double和long double,三者的区别是能够表示的有效位数不同。
- float至少32位,double至少48位,且不少于float;long double至少和double一样。
3.3.3 浮点常量
- 书写浮点常量的时候通常默认是double的,如果像定义float的,则使用f或者F后缀。
3.4 算术运算符
- 运算符就是常见的+,-,*,/等,算术运算符需要注意其结合的优先级,优先级不同则结合顺序不同。
- 对于除法运算,如果两个操作数都是整数,将执行整数除法,小数部分将被省去。如果至少有一个是浮点数,则计算结果为浮点数,保留小数部分。
#include <iostream>
using namespace std;
int main() {
int a = 10;
int b = 3;
cout << a / b << endl;
float c = 3.0f;
cout << a / c << endl;
cout << typeid(a / c).name() << endl;
double d = 3.0f;
cout << a / d << endl;
cout << typeid(a / d).name() << endl;
auto e = 1.0;
cout << typeid(e).name() << endl;
cout << typeid(e / c).name() << endl;
}
输出
3
3.33333
f
3.33333
d
d
d
从上面的例子可以看到,当一方为float类型,另一方为整型时,计算结果为float类型。一方为double类型,另一方为整型时,计算结果为double类型。auto默认将浮点数设置为double类型。float和double类型运算结果为double类型。
- 不同类型的数据在进行运算的时候会自动类型转换。也可以强制指定返回的数据的类型,强制转换的时候会采取截断读取,C++并没有定义结果应该是什么。
#include <iostream>
//#include <climits>
using namespace std;
int main() {
char a {77};
int b = a;
char c = (char) b;
char d = char (b);
cout << a <<endl;
cout << b <<endl;
cout << c <<endl;
cout << d <<endl;
return 0;
}
输出
M
77
M
M
- 强制类型转化可以有上面的两种格式。
- C++中可以使用列表初始化的方式初始化变量。
#include <iostream>
using namespace std;
int main() {
char a {77};
cout << a << endl;
return 0;
}
- C++11中auto关键字能够使编译器根据初始值来推断变量的类型,但是一般都是用于比较复杂的类型,在简单类型中使用auto可能还会出错。
3.4.4 类型转换
C++将在一下情况下执行自动类型转换:
- 将一种算数类型的值赋值给另一种算术类型的值时
- 表达式中包含不同算术类型的值时
- 将参数传递给函数时
1.初始化和赋值进行的转换
当将一种类型的值赋值给另一种类型时,值会被转换为接收变量的类型。将一个小的值赋值给大的数据类型通常不会导致什么问题,但将大的值赋值给小的数据类型的时候则会导致问题。
#include <iostream>
using namespace std;
int main() {
short a = 39;
int b = a;
cout << a << endl;
float c = b;
cout << b << endl;
float d = 3243.3243f;
double e = d;
cout << e << endl;
}
输出:
39
39
3243.32
小的数据类型向大数据类型转化的时候,通常不会有什么问题
#include <iostream>
using namespace std;
int main() {
int a = 43243244;
short b = a;
cout << b << endl;
}
输出:
-10516
潜在问题出现了,通常会导致以下问题:
- 较大的浮点数转换为小浮点数时,会丢失精度,也可能超出目标类型范围,结果不确定。
- 浮点数转换为整数,小数部分丢失,也可能超出目标范围,结果不确定。
- 较大整数转换为小整数,原来的值超出目标范围,截取右边的字节
2、列表初始化转换
int x = 66;
char a {66};
char b {x}; //not allowed
char c {5435}; //not allowed
列表初始化时,会自动判断传入的数据是否能够储存,如果无法储存则会报错。x作为一个变量,编译器无法判断其值大小,所以编译无法通过。5435超过了char表示范围,也无法编译通过。
3、表达式中的转换
自动转换,在计算表达式时,C++将bool、char、unsigned char、signed char和short值自动转换为int类型,对于bool类型,true被转换成1,false被转换成0。
short a = 10;
short b = 10;
short c = a + b;
表达式中,a和b被转换成int类型,计算完成后赋值给short类型的c。
还有一些整型提升,如果short比int短,则unsigned short被转换成int类型,如果short和int一样长,则unsigned short被转换成unsigned int,确保数据不丢失。其他的类似wchar_t也是一样的,提升到能够存储其值的一个类型。
C++11校验表如下:
- 如果一个操作数为long double,另一个操作数被提升为long double
- 如果一个操作数为double,另一个操作数被提升为double
- 如果一个操作数为lfloat,另一个操作数被提升为float
- 否则,说明两个都是整型,则做整型提升
- 如果两个都是有符号或者无符号的,如果其中一个类型更高,则另一个做类型提升
- 如果一个有符号,一个无符号,且无符号级别高,则有符号数转换成无符号数
- 如果有符号类型可表示所有无符号类型的取值,则无符号数转换成有符号数
- 否则,将两个操作数都转换成有符号类型的无符号版本