前言
终于决定重新啃一遍 C++ 的基础,巩固一下以前的知识,查漏补缺。
关于基本内置类型,C++ 定义了一套包括算术类型(arithmetic type)和空类型(void)在内的基本数据类型
以下是对 C++ Primer 书中关于基本内置类型关于算术类型以及字面值常量的一些整理。
1 算术类型
算术类型分为两类
- 整型(integral type),包括字符和布尔型在内
- 浮点型
算术类型的尺寸(该类型数据所占的比特数)在不同机器上有所差别,C++ 标准规定了尺寸的最小值,同时允许编译器赋予这些类型更大的尺寸。某一类型所占的比特数不同,他所能表示的数据范围也不同。
类型 | 含义 | 最小尺寸 | 说明 |
---|---|---|---|
bool | 布尔类型 | 未定义 | 取值为真(true)或假(false) |
char | 字符 | 8 位 | 一个 char 的空间应确保可以存放机器基本字符集中任意字符对应的数字值 |
wchar_t | 宽字符 | 16 位 | 用于扩展字符集,确保可以存放机器最大扩展字符集中的任意一个字符 |
char16_t | Unicode 字符 | 16 位 | 用于扩展字符集,为 Unicode 字符集服务 |
char32_t | Unicode 字符 | 32 位 | 用于扩展字符集,为 Unicode 字符集服务 |
short | 短整型 | 16 位 | 无 |
int | 整型 | 16位 | 一个 int 至少和 一个 short 一样大 |
long | 长整型 | 32 位 | 一个 long 至少和一个 int 一样大 |
long long | 长长整型 | 64 位 | C++11 中新定义,一个 long long 至少和 一个 long 一样大 |
float | 单精度浮点数 | 6 位有效数字 | 无 |
double | 双精度浮点数 | 10 位有效数字 | 无 |
long double | 扩展精度浮点数 | 10 位有效数字 | 常常用于有特殊浮点需求的硬件 |
其他说明
- 除字符和布尔类型之外,其他整型用于表示(可能)不同尺寸的整数
- C++标准指定了一个浮点数有效位数的最小值,然而大多数编译器都实现了更高的精度
一个简单的程序测试:
g++ 编译器版本
> g++ --version
g++.exe (MinGW.org GCC-6.3.0-1) 6.3.0
测试结果(内置类型所占字节数)
sizeof(bool) 1
sizeof(char) 1
sizeof(wchar_t) 2
sizeof(char16_t) 2
sizeof(char32_t) 4
sizeof(short) 2
sizeof(int) 4
sizeof(long) 4
sizeof(long long) 8
sizeof(float) 4
sizeof(double) 8
sizeof(long double) 12
带符号类型和无符号类型
除去布尔型和扩展的字符型外,其他的整型可以划分为
- 带符号的(signed),可以表示负数、0、正数
- 无符号的(unsigned),可以表示0、正数
short,int,long,long long (默认不加修饰时)都是带符号的,在他们前面加上 unsigned
,就可以得到无符号类型;
而字符型会有三种情况:char,signed char,unsigned char,但实际上表现形式只有两种 signed char
,unsigned char
,因为 char
在不同的编译器中会有不同的表现。(在我测试的编译器中,测试结果为 signed
)
字符型 | 表示范围 |
---|---|
signed char (8位) | -128 ~ 127 |
unsigned char (8位) | 0 ~ 255 |
2 字面值常量
字面值常量(literal),每个字面值常量都对应一种数据类型,其形式和值决定了它的数据类型。
整型字面值
整型字面值可以写作十进制数、八进制数、十六进制数的形式。下边表格展示了如何用上面的三种进制表示数值 20
进制 | 示例 | 说明 | 默认类型 | 无/带符号 |
---|---|---|---|---|
十进制 | 20 | 无 | int, long, long long 中的尺寸最小的能容纳下的 | 带符号数 |
八进制 | 024 | 以 0 开头的整数 | int, long, long long 与它们相对应的 unsigned 类型 | 两者皆有 |
十六进制 | 0x14 | 以 0x 或 0X 开头的整数 | int, long, long long 与它们相对应的 unsigned 类型 | 两者皆有 |
如果一个字面值连与之关联的最大的数据类型都放不下,将产生错误。类型 short 没有对应的字面值。
浮点型字面值
浮点型字面值表现为一个小数或以科学技术法表示的指数,其中指数用 E
或 e
标识:
3.14159
3.14159E0
0.
0e0
.001
默认的,浮点型字面值是一个 double
字符和字符串字面值
由单引号括起来的一个字符称为 char
型字面值,双引号括起来的零个或多个字符则构成字符串型字面值。
'a' //字符字面值
"Hello" //字符串字面值
字符串字面值类型实际上是由常量字符构成的数组(array),编译器在每个字符串的结尾添加一个空字符(’\0’),因此,字符串字面值的实际长度要比它的内容多 1。
如果两个字符串的字面值位置紧邻且仅由空格、缩进和换行符分隔,则他们实际上是一个整体。(一般用于字符串字面值较长写在一行不合适的情况)
cout << 'A' << sizeof('A') << endl; // sizeof == 1
cout << "A" << sizeof("A") << endl; // sizeof == 2
cout << "A\n" << sizeof("A\n") << endl; // sizeof == 3
cout << "A\t" << sizeof("A\t") << endl; // sizeof == 3
cout << "A" "B" "C" "D" << sizeof("A" "B" "C" "D") << endl; // ABCD, sizeof == 5
string str("A" "B" "C" "D");
// ABCD, sizeof == 24, length == 4, size == 4
cout << str << sizeof(str) << " " << str.length() << " " << str.size() << endl;
string str2("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
// ABCDEFGHIJKLMNOPQRSTUVWXYZ, sizeof == 24, length == 26, size == 26
cout << str2 << sizeof(str2) << " " << str2.length() << " " << str2.size() << endl;
cout << "" << sizeof("") << endl; // sizeof == 1
string str3 = "";
// , sizeof == 24, length == 0, size == 0
cout << str3 << sizeof(str3) << " " << str3.length() << " " << str3.size() << endl;
转义序列
有两类字符程序员不能直接使用
- 不可打印(nonprintable)的字符,如退格或其他控制字符,因为它们没有可视的图符
- 在 C++ 中有特殊含义的字符(单引号,双引号,问号,反斜线),在这种情况下需要用到转义序列(escape sequence)
转义序列均以反斜线作为开始,C++ 语言规定的转义序列包括:
字符 | 转义序列 |
---|---|
换行符 | \n |
横向制表符 | \t |
纵向制表符 | \v |
反斜线 | \\ |
回车符 | \r |
退格符 | \b |
问号 | \? |
双引号 | \" |
单引号 | \’ |
进纸符 | \f |
报警(响铃)符 | \a |
另外还有泛化的转义序列,形式为:
\x
后紧跟 1 个或多个十六进制数字\
后紧跟 1 个、2 个或 3 个八进制数字
cout << "HI \x4dO\115!\n"; // HI MOM!,然后换行
cout << "\a\n"; // Windows下确实有响铃的声音(dengdong)
cout << "\1234"; // S4,由于 \ 后面跟着的数字超过 3 个,只有前 3 个数字和 \ 构成了转义序列
指定字面值的类型
如下表中所列的前缀和后缀,可以改变整型、浮点型和字符型字面值的默认类型
字符串和字符串字面值
前缀 | 含义 | 类型 |
---|---|---|
u | Unicode 16 字符 | char16_t |
U | Unicode 32 字符 | char32_t |
L | 宽字符 | wchar_t |
u8 | UTF-8(仅用于字符串字面值常量) | char |
整型字面值
后缀 | 最小匹配类型 |
---|---|
u or U | unsigned |
l or L | long |
ll or LL | long long |
浮点型字面值
后缀 | 类型 |
---|---|
f or F | float |
l or L | long double |
L'a' //宽字符型字面值,类型是 wchar_t
u8"hi!" //utf-8 字符串字面值(utf-8 用 8 位编码一个 Unicode 字符)
42ULL //无符号整型字面值,类型是 unsigned long long
1E-3F //单精度浮点型字面值,类型是 float
3.14159L //扩展精度浮点型字面值,类型是 long double
注:对于整型字面值,我们能分别指定它是否带符号以及占用多少空间。另外 U 和 L 可结合在一起使用,如前面的例子一样。不过注意看表格中写的是最小匹配类型,故如果以 U 为后缀,则根据情况匹配 unsigned int, unsigned long, unsigned long long 中的一个作为其数据类型。
布尔字面值和指针字面值
true
和 false
是布尔类型的字面值
nullptr
是指针字面值(C++ 11 新标准,最好使用这个,而避免使用 NULL)
参考资料
[1] C++ Primer(第5版)中文版 p30~38 基本内置类型
一些测试
下面程序的注释基于编译器:
> g++ --version
g++.exe (MinGW.org GCC-6.3.0-1) 6.3.0
基本数据类型大小
#include <iostream>
using namespace std;
int main() {
//输出位字节数
cout << "sizeof(bool) " << sizeof(bool) << endl // 1
<< "sizeof(char) " << sizeof(char) << endl // 1
<< "sizeof(wchar_t) " << sizeof(wchar_t) << endl // 2
<< "sizeof(char16_t) " << sizeof(char16_t) << endl // 2
<< "sizeof(char32_t) " << sizeof(char32_t) << endl // 4
<< "sizeof(short) " << sizeof(short) << endl // 2
<< "sizeof(int) " << sizeof(int) << endl // 4
<< "sizeof(long) " << sizeof(long) << endl // 4
<< "sizeof(long long) " << sizeof(long long) << endl // 8
<< "sizeof(float) " << sizeof(float) << endl // 4
<< "sizeof(double) " << sizeof(double) << endl // 8
<< "sizeof(long double) " << sizeof(long double) << endl; // 12
}
判断编译器 char
的表现类型
void char_type() {
char ch = 0xFF;
if(ch == -1) {
cout << "signed\n";
}
else if(ch == 255) {
cout << "unsigned\n";
}
else cout << "error\n";
}
// 测试结果为 signed
对字符型赋值的测试
char ch1 = -129; //warning: overflow in implicit constant conversion [-Woverflow]
char ch2 = -128;
char ch3 = -127;
char ch4 = 127;
char ch5 = 128;
char ch6 = 129;
char ch7 = 255;
char ch8 = 256; //warning: overflow in implicit constant conversion [-Woverflow]
signed char ch9 = -129; //warning: overflow in implicit constant conversion [-Woverflow]
signed char ch10 = -128;
signed char ch11 = -127;
signed char ch12 = 127;
signed char ch13 = 128;
signed char ch14 = 129;
signed char ch15 = 255;
signed char ch16 = 256; //warning: overflow in implicit constant conversion [-Woverflow]
unsigned char ch17 = -129; //warning: large integer implicitly truncated to unsigned type [-Woverflow]
unsigned char ch18 = -128;
unsigned char ch19 = -127;
unsigned char ch20 = 255;
unsigned char ch21 = 256; //warning: large integer implicitly truncated to unsigned type [-Woverflow]