这一集视频我们来看一下第二章的第一节。从这一集视频开始,我决定只讲代码和我认为需要挑出来讲解的难点/细节,对于难点和细节,我决定以提出问题和解决问题的形式来呈现。关于代码,基本只讲书上出现过的代码,实在有需要我再自己补充代码。毕竟基础知识的话,我觉得书上写的已经足够详细了,我再复述一遍没什么太多的意义,所以,大家看书的话,常看常新呀,总之就是一定要常看。
因为代码是更加直观的东西,并且,我们最终都是要去实际地写代码的。所以,我这里将着重去讲解书上出现的每一处代码,我认为能够理解代码,并且把这些代码实际应用到我们实际的项目中去,这才是真正有意义的事情。
如果我们能做到完全理解书上的这些代码,做到看到这些代码时心中有底,我觉得那就是胜利。同时,如果习题里面有涉及代码的部分,我们也不会错过。
尽量做到:一切都在代码中。这样,如果有人问,你读过这本书吗?我们可以很有底气地说,读过,毕竟,代码全都掌握了,难道还不算读过吗?
这里还要额外多说一点,就是,从这一章开始,我在视频中演示代码所使用的编辑器将换到 neovim + neovide 这样一个组合,然后,在 Windows 平台下,我会使用 pwsh 也就是 powershell 脚本来进行自动化编译和运行,而在 Linux 中,我将使用 shell 脚本来自动化编译和运行。当然,构建工具使用的肯定是 cmake。
那么,就直接看代码吧。
说明:代码的命名规范依然以英文原版书中出现的代码的页码为指导原则。
Part1
英文原书 p32,
1#include <iostream>
2
3int main()
4{
5 int i = 1;
6 int j = 2;
7 i = i + j;
8 std::cout << i << std::endl;
9
10 return 0;
11}
个人对英文原书 32 页补充代码,custom_p32.cpp,
1#include <iostream>
2
3int main()
4{
5 // bool 类型,通常大小为 1 个字节
6 bool boolean = true;
7 std::cout << "bool: " << boolean << " (size: " << sizeof(boolean) << " bytes)" << std::endl;
8
9 // char 类型,8 bits
10 char character = 'A';
11 std::cout << "char: " << character << " (size: " << sizeof(character) << " bytes)" << std::endl;
12
13 // wchar_t 类型,宽字符,16 bits 或 32 bits,取决于平台
14 wchar_t wide_character = L'A';
15 std::wcout << "wchar_t: " << wide_character << " (size: " << sizeof(wide_character) << " bytes)" << std::endl;
16
17 // char16_t 类型,16 bits Unicode 字符
18 char16_t unicode_16 = u'A';
19 std::wcout << "char16_t: " << static_cast<wchar_t>(unicode_16) << " (size: " << sizeof(unicode_16) << " bytes)" << std::endl;
20
21 // char32_t 类型,32 bits Unicode 字符
22 char32_t unicode_32 = U'A';
23 std::wcout << "char32_t: " << static_cast<wchar_t>(unicode_32) << " (size: " << sizeof(unicode_32) << " bytes)" << std::endl;
24
25 // short 整数类型,16 bits
26 short short_integer = 16;
27 std::cout << "short: " << short_integer << " (size: " << sizeof(short_integer) << " bytes)" << std::endl;
28
29 // int 整数类型,通常至少为 32 bits,但某些系统上可能为 16 bits
30 int integer = 26;
31 std::cout << "int: " << integer << " (size: " << sizeof(integer) << " bytes)" << std::endl;
32
33 // long 整数类型,通常为 32 bits
34 long long_integer = 36;
35 std::cout << "long: " << long_integer << " (size: " << sizeof(long_integer) << " bytes)" << std::endl;
36
37 // long long 整数类型,64 bits
38 long long long_long_integer = 46LL;
39 std::cout << "long long: " << long_long_integer << " (size: " << sizeof(long_long_integer) << " bytes)" << std::endl;
40
41 // float 单精度浮点数,精度为 6 位有效数字
42 float single_precision = 3.1f;
43 std::cout << "float: " << single_precision << " (size: " << sizeof(single_precision) << " bytes, precision: " << FLT_DIG << " significant digits)" << std::endl;
44
45 // double 双精度浮点数,精度为 10 位有效数字
46 double double_precision = 3.14;
47 std::cout << "double: " << double_precision << " (size: " << sizeof(double_precision) << " bytes, precision: " << DBL_DIG << " significant digits)" << std::endl;
48
49 // long double 扩展精度浮点数,通常与 double 相同,但某些系统上可能有更高精度
50 long double extended_precision = 3.1415L;
51 std::cout << "long double: " << extended_precision << " (size: " << sizeof(extended_precision) << " bytes, precision: " << LDBL_DIG << " significant digits)" << std::endl;
52
53 return 0;
54}
关于这些基本类型,如果有时间的话,推荐大家去看《深入理解计算机系统(第三版)》这本书,英文名是:Computer Systems: A Programmer’s Perspective (3rd Edition),也就是大名鼎鼎的 CSAPP。就拿浮点数来说,这个是我当时完整看过的,所以能够安心地给出评价,那就是如果你想理解浮点数真正的构造及原理,那么,可以抽空看一下这本书。
那么,如果仅仅停留在本书需要理解的程度,那么,我们就像上面这样写几行代码就可以了解怎么去使用了,
使用微软的 MSVC 编译器运行的结果如下,
1bool: 1 (size: 1 bytes)
2char: A (size: 1 bytes)
3wchar_t: A (size: 2 bytes)
4char16_t: A (size: 2 bytes)
5char32_t: A (size: 4 bytes)
6short: 16 (size: 2 bytes)
7int: 26 (size: 4 bytes)
8long: 36 (size: 4 bytes)
9long long: 46 (size: 8 bytes)
10float: 3.1 (size: 4 bytes, precision: 6 significant digits)
11double: 3.14 (size: 8 bytes, precision: 15 significant digits)
12long double: 3.1415 (size: 8 bytes, precision: 15 significant digits)
这里为什么有些尺寸感觉和书上有差异呢?因为书上写的是标准规定的只是最小尺寸,然后在此基础上编译器可以自由发挥。
Part2 类型转换
p35,
1#include <iostream>
2
3int main()
4{
5 bool b = 42; // b is true
6 std::cout << b << std::endl;
7 int i = b; // i has value 1
8 std::cout << i << std::endl;
9 i = 3.14; // i has value 3
10 std::cout << i << std::endl;
11 double pi = i; // pi has value 3.0
12 std::cout << pi << std::endl;
13 unsigned char c = -1; // assuming 8-bit chars, c has value 255
14 std::cout << c << std::endl;
15 std::cout << static_cast<int>(c) << std::endl;
16 signed char c2 = 256; // assuming 8-bit chars, the value of c2 is undefined
17 std::cout << c2 << std::endl;
18 std::cout << static_cast<int>(c2) << std::endl;
19 return 0;
20}
p36_1,
1#include <iostream>
2
3int main()
4{
5 int i = 42;
6 std::cout << i << std::endl;
7 if (i) // condition will evaluate as true
8 i = 0;
9 std::cout << i << std::endl;
10 return 0;
11}
p36_2,
1#include <iostream>
2
3int main()
4{
5 unsigned u = 10;
6 int i = -42;
7 std::cout << i + i << std::endl; // prints -84
8 std::cout << u + i << std::endl; // if 32-bit ints, prints 4294967264
9
10 return 0;
11}
这里书上的解释有点问题,英文原版里面是让我们去看上面的案例,这里中文翻译多给了一些解释,但是这个解释不太能够让人理解,我们还是按照上面的取模的解释来。而对于给负数取模,我们可以把其想象成反方向拨动时钟,然后,从 0 到指针之间的距离就是我们所求的取模后的余数。
p37_01,
1#include <iostream>
2
3int main()
4{
5 unsigned u1 = 42, u2 = 10;
6 std::cout << u1 - u2 << std::endl; // ok: result is 32
7 std::cout << u2 - u1 << std::endl; // ok: but the result will wrap around
8
9 return 0;
10}
p37_02,
1// 这里需要看一下中文版 p11 也的练习题第 2 题
2#include <iostream>
3
4int main(int argc, char *argv[])
5{
6 for (int i = 10; i >= 0; --i)
7 std::cout << i << std::endl;
8
9 return 0;
10}
按:这里可以到 1.4.1 节(英文 p13)的练习那里去看一下。
p37_03,
1#include <iostream>
2
3int main()
4{
5 /*
6 // WRONG: u can never be less than 0; the condition will always succeed
7 for (unsigned u = 10; u >= 0; --u)
8 std::cout << u << std::endl;
9 */
10 return 0;
11}
p37_04,
1#include <iostream>
2
3int main()
4{
5 unsigned u = 11; // start the loop one past the first element we want to print
6 while (u > 0)
7 {
8 --u; // decrement first, so that the last iteration will print 0
9 std::cout << u << std::endl;
10 }
11
12 return 0;
13}
Part3 字面值常量
p38_01,
1#include <iostream>
2
3int main()
4{
5 int a = 20; // 十进制
6 int b = 024; // 八进制
7 int c = 0x14; // 十六进制
8 std::cout << a << ", " << b << ", " << c << std::endl;
9 return 0;
10}
p38_02,
1#include <iostream>
2
3int main()
4{
5 double a = 3.14159;
6 double b = 3.14159E0;
7 double c = 0.;
8 double d = 0e0;
9 double e = .001;
10 std::cout << a << ", " << b << ", " << c << ", " << d << ", " << e << std::endl;
11 return 0;
12}
p39_01,
1#include <iostream>
2#include <string>
3
4int main()
5{
6 char a = 'a';
7 std::string b = "Hello World!";
8 std::cout << a << ", " << b << std::endl;
9 return 0;
10}
p39_02,
1#include <iostream>
2
3int main()
4{
5 // multiline string literal
6 std::cout << "a really, really long string literal "
7 "that spans two lines" << std::endl;
8 return 0;
9}
p39_03,
1#include <cstdio>
2#include <iostream>
3
4int main()
5{
6 std::cout << "Hello\nWorld" << std::endl;
7 std::cout << "Name\tAge" << std::endl;
8 std::cout << "\a" << std::endl;
9 std::cout << "Hello\vWorld" << std::endl;
10 std::cout << "Helloo\b World" << std::endl;
11 std::cout << "He said, \"Hello!\"" << std::endl;
12 std::cout << "C:\\Program Files" << std::endl;
13 std::cout << "What\?" << std::endl;
14 std::cout << "It\'s a cat" << std::endl;
15 std::cout << "Hello\rWorld" << std::endl;
16 std::cout << "Hello\fWorld" << std::endl;
17 getchar();
18 return 0;
19}
p39_04,
1#include <iostream>
2
3int main()
4{
5 std::cout << '\n'; // prints a newline
6 std::cout << "\tHi!\n"; // prints a tab followd by "Hi!" and a newline
7 return 0;
8}
p39_05,
1#include <iostream>
2
3int main()
4{
5 std::cout << "\7"; // 在一些环境下会发出提示音,和 \a 相同
6 std::cout << "Hello\12World"; // 输出:
7 // Hello
8 // World
9 // 实际效果等同于 \n
10
11 std::cout << "Hello\40World"; // 输出:Hello World (插入一个空格)
12
13 char str[] = "Hello\0World";
14 std::cout << str; // 输出:Hello (由于\0表示字符串结束,World部分不会被输出)
15
16 std::cout << "\115"; // 输出:M
17
18 std::cout << "\x4d"; // 输出:M
19 return 0;
20}
p40_01,
1#include <iostream>
2
3int main()
4{
5 std::cout << "Hi \x4dO\115!\n"; // prints Hi MOM! followed by a newline
6 std::cout << '\115' << '\n'; // prints M followed by a newline
7 return 0;
8}
p40_02,
1#include <iostream>
2
3int main()
4{
5 // 1. L'a' - wide character literal (wchar_t)
6 wchar_t wideChar = L'a';
7 std::wcout << L"Wide character literal: " << wideChar << std::endl;
8
9 // 2. u8"hi!" - UTF-8 string literal
10 const char *utf8String = u8"hi!";
11 std::cout << "UTF-8 string literal: " << utf8String << std::endl;
12
13 // 3. 42ULL - unsigned long long literal
14 unsigned long long ullValue = 42ULL;
15 std::cout << "Unsigned long long literal: " << ullValue << std::endl;
16
17 // 4. 1E-3F - single-precision floating-point literal (float)
18 float floatValue = 1E-3F;
19 std::cout << "Single-precision floating-point literal: " << floatValue << std::endl;
20
21 // 5. 3.14159L - extended-precision floating-point literal (long double)
22 long double longDoubleValue = 3.14159L;
23 std::cout << "Extended-precision floating-point literal: " << longDoubleValue << std::endl;
24
25 return 0;
26}
p41,
1#include <iostream>
2
3int main() {
4
5 bool test = false;
6 std::cout << test << std::endl;
7 return 0;
8}