C++初学者指南第一步---4.基本类型
文章目录
- C++初学者指南第一步---4.基本类型
-
- 1.变量声明
- 2.快速概览
-
- [Booleans 布尔型](#Booleans 布尔型)
- [Characters 字符型](#Characters 字符型)
- [Signed Integers 有符号整数](#Signed Integers 有符号整数)
- [Unsigned Integers 无符号整数](#Unsigned Integers 无符号整数)
- [Floating Point Types 浮点数类型](#Floating Point Types 浮点数类型)
- [3.Common Number Representations 常用的数字表示常用数字的表示方法](#3.Common Number Representations 常用的数字表示常用数字的表示方法)
- [4.Arithmetic Operations 算术运算](#4.Arithmetic Operations 算术运算)
-
- [Increment/Decrement 递增/递减](#Increment/Decrement 递增/递减)
- [5.Comparisons 比较运算](#5.Comparisons 比较运算)
-
- [2-way Comparisons 二元比较](#2-way Comparisons 二元比较)
- [3-Way Comparisons With <=> 三元比较用<=> C++20](#3-Way Comparisons With <=> 三元比较用<=> C++20)
- 6.布尔型逻辑运算
- 7.基础类型的内存大小
- [8.std::numeric_limits<type> (数值范围模板类)](#8.std::numeric_limits<type> (数值范围模板类))
- [9.Type Narrowing类型缩小(类型窄化)](#9.Type Narrowing类型缩小(类型窄化))
- 10.花括号初始化(统一初始化)C++11
- 11.位运算
-
- [Bitwise Logic 按位逻辑运算](#Bitwise Logic 按位逻辑运算)
- [Bitwise Shifts 按位移位](#Bitwise Shifts 按位移位)
- 12.算术转换和提升
基本类型是所有复杂类型(如列表、哈希映射、树、图等)的基本构建块。
1.变量声明
变量声明的基本语法
java
type variable = value;
type variable {value}; C++11
java
// 声明 & 初始化 'i':
int i = 1;
// 打印'i'的值:
cout << i << '\n';
int j {5};
cout << j << '\n';
注意:基本类型的变量默认不会被初始化!
java
int k; // k不会被初始化!
cout << k << '\n'; // k可能是任何值
因为在c++中,你只需要为你使用的内存付出代价(大内存块的初始化可能相当昂贵)。
注意:但是: 在声明变量时,你几乎总是需要对其进行初始化,以防止出现bug!
2.快速概览
Booleans 布尔型
java
bool b1 = true;
bool b2 = false;
Characters 字符型
- 最小整数;通常为1字节
- 在x86/x86_64平台上,signed(有符合) 类型值的范围为[-128,127]。
Signed Integers 有符号整数
n bits ⇒ values ∈ [ − 2 n − 1 -2^{n-1} −2n−1, 2 n − 1 2^{n-1} 2n−1-1]
n位数 ⇒ 值属于 [ − 2 n − 1 -2^{n-1} −2n−1, 2 n − 1 2^{n-1} 2n−1-1] 的范围
java
short s = 7;
int i = 12347;
long l1 = -7856974990L;
long long l2 = 89565656974990LL;
// ' C++14增加的数字分隔符,
long l3 = 512'232'697'499;
Unsigned Integers 无符号整数
n bits ⇒ values ∈ [0, 2 n − 1 2^{n-1} 2n−1]
n位数 ⇒ 值属于 [0, 2 n − 1 2^{n-1} 2n−1] 的范围
java
unsigned u1 = 12347U;
unsigned long u2 = 123478912345UL;
unsigned long long u3 = 123478912345ULL;
// 非10进制
unsigned x = 0x4A; // 16进制
unsigned b = 0b10110101; // 二进制 C++14
Floating Point Types 浮点数类型
- float 通常为IEEE 754格式32位。
- double 通常为IEEE 754格式64位。
- long double 在x86/x86-64上通常为80位。
java
float f = 1.88f;
double d1 = 3.5e38;
long double d2 = 3.5e38L; C++11
// ' digit separator C++14
double d3 = 512'232'697'499.052;
3.Common Number Representations 常用的数字表示常用数字的表示方法
4.Arithmetic Operations 算术运算
- 表达式 a ⊕ b 返回操作⊕应用于 a 和 b值的结果
- 表达式 a ⊕= b 存储 a中操作⊕的结果
代码 | 注释 |
---|---|
int a = 4; int b = 3; | 变量a设置为值4 变量b设置为值3 |
a = a + b; a += b; | a: 7 加法运算 a: 10 |
a = a - b; a -= b; | a: 7 减法运算 a: 4 |
a = a * b; a *= b; | a: 12 乘法运算 a: 36 |
a = a / b; a /= b; | a: 12 除法运算 a: 4 |
a = a % b; | a: 1 除法余数运算(取模) |
Increment/Decrement 递增/递减
- 将值更改为递增1/递减 1
- 前缀表达式 ++x / --x 返回新的(递增/递减)值
- 后缀表达式 x++ / x-- 增加/减少值,但返回旧值
代码 | 注释 |
---|---|
int a = 4; int b = 3; | a: 4 b: 3 |
b = a++; b = ++a; | a: 5 b: 4 a: 6 b: 6 |
5.Comparisons 比较运算
2-way Comparisons 二元比较
比较结果为 true 或 false
代码 | 注释 |
---|---|
int x = 10; int y = 5; | |
bool b1 = (x == 5); bool b2 = (x != 6); | false 相等比较 true 不相等比较 |
bool b3 = x > y; bool b4 = x < y; bool b5 = y >= 5; bool b6 = x <= 30; | true 大于比较 false 小于比较 true 大于等于比较 true 小于等于比较 |
3-Way Comparisons With <=> 三元比较用<=> C++20
确定 2 个对象的相对顺序:
(a <=> b) < 0 如果 a < b
(a <=> b) > 0 如果 a > b
(a <=> b) == 0 如果 a 和 b 相等
- 三元比较返回一个可与字面量 0 比较的比较类别值
- 返回的值来自三种可能的类别之一:std::strong_ordering、std::weak_ordering 或 std::partial_ordering
4 <=> 6 → std::strong_ordering::less
5 <=> 5 → std::strong_ordering::equal
8 <=> 1 → std::strong_ordering::greater
6.布尔型逻辑运算
操作符
java
bool a = true;
bool b = false;
bool c = a && b; // false 逻辑与 AND
bool d = a || b; // true 逻辑或 OR
bool e = !a; // false 逻辑非 NOT
// 备选的拼写:
bool x = a and b; // false
bool y = a or b; // true
bool z = not a; // false
转换为布尔型
- 0 始终为 false;
- 其他一切都是true;
java
bool f = 12; // true (int → bool)
bool g = 0; // false (int → bool)
bool h = 1.2; // true (double → bool)
短路求值
如果出现以下情况,则不计算布尔比较的第二个操作数 在计算第一个操作数后,结果已经知道了。
java
int i = 2;
int k = 8;
bool b1 = (i > 0) || (k < 3);
i > 0 已经是true ,k < 3不计算,因为逻辑或的结果已经是true。
7.基础类型的内存大小
所有类型大小都是 sizeof(char) 的倍数
java
cout << sizeof(char); // 1
cout << sizeof(bool); // 1
cout << sizeof(short); // 2
cout << sizeof(int); // 4
cout << sizeof(long); // 8
// number of bits in a char
cout << CHAR_BIT; // 8
char c = 'A';
bool b = true;
int i = 1234;
long l = 12;
short s = 8;
大小取决于平台
C++仅提供基本保证
- sizeof(short) ≥ sizeof(char)
- sizeof(short) ≥ sizeof(char)
- sizeof(int) ≥ sizeof(short)
- sizeof(int) ≥ sizeof(short)
- sizeof(long) ≥ sizeof(int)
- sizeof(long) ≥ sizeof(int)
例如,在某些 32 位平台上: int = long
整数大小保证 C++11
java
#include <cstdint>
- 精确尺寸(在某些平台上不可用)
int8_t, int16_t, int32_t, int64_t, uint8_t, ... - 保证最小尺寸
int_least8_t, uint_least8_t, ... - 速度最快且保证最小尺寸
int_fast8_t, uint_fast8_t, ...
固定宽度浮点类型保证 C++23
java
#include <stdfloat>
// storage bits: sign + exponent + mantissa(存储位: 符号 + 指数 + 尾数)
std::float16_t a = 12.3f16; // 1 + 5 + 10 = 16 bits = 2 B
std::float32_t b = 12.3f32; // 1 + 8 + 23 = 32 bits = 4 B
std::float64_t c = 12.3f64; // 1 + 11 + 52 = 64 bits = 8 B
std::float128_t d = 12.3f128; // 1 + 15 + 112 = 128 bits = 16 B
std::bfloat16_t e = 12.3b16; // 1 + 8 + 7 = 16 bits = 2 B
8.std::numeric_limits (数值范围模板类)
java
#include <limits>
// smallest negative value:(double类型的最小负值)
cout << std::numeric_limits<double>::lowest();
// float/double: smallest value > 0 (float/double类型的最小正值)
// integers: smallest value
cout << std::numeric_limits<double>::min();
// largest positive value:(可以表示的最大正值)
cout << std::numeric_limits<double>::max();
// smallest difference btw. 1 and next value:(1和下一个值之间最小差值,用于浮点数比较)
cout << std::numeric_limits<double>::epsilon();
...
9.Type Narrowing类型缩小(类型窄化)
- 从可以表示更多值的类型转换为可以表示更少值的类型
- 可能会导致信息丢失
- 一般来说,没有编译器警告------默默地发生
- 隐藏的潜在运行时错误来源
java
double d = 1.23456;
float f = 2.53f;
unsigned u = 120u;
double e = f; // OK float → double
int i = 2.5; // 缩小 double → int
int j = u; // 缩小 unsigned int → int
int k = f; // 缩小 float → int
10.花括号初始化(统一初始化)C++11
java
type variable { value };
- 适用于所有基本类型
- 缩小转换 ⇒ 编译器警告
java
double d {1.23456}; // OK
float f {2.53f}; // OK
unsigned u {120u}; // OK
double e {f}; // OK float → double
int i {2.5}; // COMPILER WARNING: double → int
int j {u}; // COMPILER WARNING: unsigned int → int
int k {f}; // COMPILER WARNING: float → int
注意:确保防止静默类型转换,特别是将无符号整数转换缩小为有符号整数转换------它们会导致难以发现的运行时错误!
11.位运算
Bitwise Logic 按位逻辑运算
表达式 | 说明 |
---|---|
a & b | AND按位与 |
a | b | OR按位或 |
a ^ b | XOR按位异或 |
~a | NOT按位反(反码) |
java
#include <cstdint>
std::uint8_t a = 6;
std::uint8_t b = 0b00001011;
std::uint8_t c1 = (a & b); // 2
std::uint8_t c2 = (a | b); // 15
std::uint8_t c3 = (a ^ b); // 13
std::uint8_t c4 = ~a; // 249
std::uint8_t c5 = ~b; // 244
// test if int is even/odd:
bool a_odd = a & 1;
bool a_even = !(a & 1);
memory bits:
0000 0110
0000 1011
0000 0010
0000 1111
0000 1101
1111 1001
1111 0100
result:
0 ⇒ false
1 ⇒ true
Bitwise Shifts 按位移位
表达式 | 说明 |
---|---|
x << n | 返回 x 的值,其位向左移动 n 位 |
x >> n | 返回 x 的值,其位向右移动 n 位 |
x <<= n | 通过向左移动 n 位来修改 x |
x >>= n | 通过向右移动 n 位来修改 x |
java
#include <cstdint>
std::uint8_t a = 1;
a <<= 6; // 64
a >>= 4; // 4
std::uint8_t b1 = (1 << 1); // 2
std::uint8_t b2 = (1 << 2); // 4
std::uint8_t b3 = (1 << 4); // 16
shell
memory bits:
0000 0001
0100 0000
0000 0100
0000 0010
0000 0100
0001 0000
注意:把一个数据类型为N位的对象移动N位或更多位是未定义行为!
java
std::uint32_t i = 1; // 32 bit type
i <<= 32; 未定义行为!
std::uint64_t j = 1; // 64 bit type
j <<= 70; 未定义行为!
12.算术转换和提升
很遗憾,这里有一大堆规则(可以追溯到C语言)的目的是确定二元运算的两个操作数和结果的共同类型
Operand A ⊕ Operand B → Result
简单总结
涉及至少一种浮点类型的运算
- long double ⊕ any other type → long double
- double ⊕ float → double
- double ⊕ any integer → double
- float ⊕ any integer → float
两种整数类型的运算
- 先对两个操作数执行整数提升:基本上任何小于int的值都会被提升为int或unsigned int(取决于哪一种类型可以表示未提升类型的所有值)
- 如果两个操作数类型不同,则应用整数转换:
- 两个有符号:较小类型转换为较大类型
- 两个无符号:较小类型转换为较大类型
- 有符号 ⊕ 无符号:
- 如果两者位宽相同,有符号转换为无符号
- 否则,如果无符号类型可以表示有符号类型的所有值,无符号转换为有符号
- 否则,两者都转换为无符号
附上原文链接
翻译和整理文章不易,如果文章对您有用请随手点个赞,谢谢!