├── 01|快速回顾:一个 C 程序的完整生命周期.md ├── 02|程序基石:数据与量值是如何被组织的?.md ├── 03|计算单元:运算符是如何工作的?.md ├── 04|控制逻辑:表达式和语句是如何协调程序运行的?.md ├── 05|代码封装(上):函数是如何被调用的?.md ├── 06|代码封装(下):函数是如何被调用的?.md ├── 07|整合数据:枚举、结构与联合是如何实现的?.md ├── 08|操控资源:指针是如何灵活使用内存的?.md ├── 09|编译准备:预处理器是怎样处理程序代码的?.md ├── 10 | 标准库:字符、字符串处理与数学计算.md ├── 11|标准库:深入理解标准 IO.md ├── 12|标准库:非本地跳转与可变参数是怎样实现的?.md ├── 13|标准库:你需要了解的 C 并发编程基础知识有哪些?.md ├── 14|标准库:如何使用互斥量等技术协调线程运行?.md ├── 15|标准库:信号与操作系统软中断有什么关系?.md ├── 16|标准库:日期、时间与实用函数.md ├── 17|标准库:断言、错误处理与对齐.md ├── 18|极致优化(上):如何实现高性能的 C 程序?.md ├── 19|极致优化(下):如何实现高性能的 C 程序?.md ├── 22|生产加速:如何使用结构化编译加速 C 项目构建? ├── CMakeLists.txt ├── Makefile ├── bin │ └── .gitkeep ├── build │ └── .gitkeep ├── include │ └── mod.h └── src │ ├── main.c │ └── mod.c ├── 25|可执行二进制文件里有什么?.md ├── 27 | 编译器在链接程序时发生了什么?.md ├── 28|程序可以在运行时进行链接吗?.md ├── 30|ABI 与 API 究竟有什么区别?.md ├── 31|程序如何与操作系统交互?.md ├── LICENSE ├── README.md ├── 开篇词.md └── 课前热身.md /01|快速回顾:一个 C 程序的完整生命周期.md: -------------------------------------------------------------------------------- 1 | * 用一个程序快速回顾 C 核心语法 - 0x1: 2 | ```c 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define BOOL_TRUE 1 // 定义用到的宏常量与宏函数; 10 | #define BOOL_FALSE 0 11 | #define typename(x) _Generic((x), \ 12 | unsigned short: "unsigned short int", \ 13 | unsigned long: "unsigned long int", \ 14 | default: "unknown") 15 | 16 | typedef enum { Host, IP } IP_ADDR_TYPE; // 定义枚举类型 IP_ADDR_TYPE,用于表示联合中生效的字段; 17 | typedef struct { // 定义结构 CONN; 18 | size_t id; 19 | uint16_t port; 20 | bool closed; 21 | IP_ADDR_TYPE addr_type; 22 | union { 23 | char host_name[256]; 24 | char ip[24]; 25 | }; 26 | } CONN; 27 | 28 | inline static const char* findAddr(const CONN* pip) { // 定义函数 findAddr,用于打印 CONN 对象的信息; 29 | assert(pip != NULL); // 运行时断言,判断传入的 CONN 指针是否有效; 30 | return pip->addr_type == Host ? pip->host_name : pip->ip; 31 | } 32 | 33 | int main(int argc, char* argv[]) { // 入口函数; 34 | static_assert(sizeof(CONN) <= 0x400, "the size of CONN object exceeds limit."); // 静态断言,判断 CONN 对象的大小是否符合要求; 35 | const CONN conns[] = { // 构造一个数组,包含三个 CONN 对象; 36 | [2] = { 1, 80, BOOL_TRUE, IP, { .ip = "127.0.0.1" } }, 37 | [0] = { 2, 8080, BOOL_FALSE, IP, { .ip = "192.168.1.1" } }, 38 | { 3, 8088, BOOL_FALSE, Host, { .host_name = "http://localhost/" } } 39 | }; 40 | 41 | for (size_t i = 0; i < (sizeof(conns) / sizeof(CONN)); ++i) { // 遍历上述 CONN 数组,并打印其中的内容; 42 | printf( 43 | "Port: %d\n" 44 | "Host/Addr: %s\n" 45 | "Internal type of `id` is: %s\n\n", 46 | conns[i].port, 47 | findAddr(&conns[i]), 48 | typename(conns[i].id) 49 | ); 50 | } 51 | return EXIT_SUCCESS; 52 | } 53 | ``` 54 | 55 | * C 语言的编程范式是怎样的? - 0x1: 56 | ```c 57 | #define ARR_LEN 5 58 | int main(void) { 59 | int arr[ARR_LEN] = { 1, 5, 10, 9, 0 }; 60 | for (int i = 0; i < ARR_LEN; ++i) { 61 | if (arr[i] > 7) { 62 | // save this element somewhere else. 63 | } 64 | } 65 | return 0; 66 | } 67 | ``` 68 | 69 | * C 语言的编程范式是怎样的? - 0x2: 70 | ```c 71 | #define ARR_LEN 5 72 | int main(void) { 73 | int arr[ARR_LEN] = { 1, 5, 10, 9, 0 }; 74 | for (int i = 0; i < ARR_LEN; ++i) { 75 | if (arr[i] > 7) { 76 | // save this element somewhere else. 77 | } 78 | } 79 | return 0; 80 | } 81 | ``` 82 | 83 | * C 语言的编程范式是怎样的? - 0x3: 84 | ```javascript 85 | let arr = [1, 5, 10, 9, 0] 86 | let result = arr.filter(n => n > 7) 87 | ``` 88 | -------------------------------------------------------------------------------- /02|程序基石:数据与量值是如何被组织的?.md: -------------------------------------------------------------------------------- 1 | * C 语言中的量值与数据 - 0x1: 2 | ```c 3 | int x = -10; // 定义一个整型变量; 4 | char y = 'c'; // 定义一个字符变量; 5 | double z = 2.0; // 定义一个双精度浮点变量; 6 | ``` 7 | 8 | * C 语言中的量值与数据 - 0x2: 9 | ```c 10 | unsigned int ux = 10; 11 | ``` 12 | 13 | * C 语言中的量值与数据 - 0x3: 14 | ```c 15 | const int vx = 10; 16 | const int* px = &vx; 17 | ``` 18 | 19 | * C 语言中的量值与数据 - 0x4: 20 | ```c 21 | #include 22 | int main(void) { 23 | const int vx = 10; 24 | const int vy = 10; 25 | int arr[vx] = {1, 2, 3}; // [错误1] 使用非常量表达式定义定长数组; 26 | switch(vy) { 27 | case vx: { // [错误2] 非常量表达式应用于 case 语句; 28 | printf("Value matched!"); 29 | break; 30 | } 31 | } 32 | return 0; 33 | } 34 | ``` 35 | 36 | * 数据的存储形式 - 0x1: 37 | ```c 38 | #include 39 | int main(void) { 40 | signed char x = -10; 41 | unsigned char y = (unsigned char)x; 42 | printf("%d\n", y); // output: 246. 43 | return 0; 44 | } 45 | ``` 46 | 47 | * 数据的存储形式 - 0x2: 48 | ```c 49 | #include 50 | int main(void) { 51 | int x = -10; 52 | unsigned int y = 1; 53 | if (x < y) { 54 | printf("x is smaller than y."); 55 | } else { 56 | printf("x is bigger than y."); // this branch is picked! 57 | } 58 | return 0; 59 | } 60 | ``` 61 | -------------------------------------------------------------------------------- /03|计算单元:运算符是如何工作的?.md: -------------------------------------------------------------------------------- 1 | * 算数、关系、位、赋值运算符 - 0x1: 2 | ```c 3 | #include 4 | #include 5 | void foo(int x, int y) { 6 | int arithmetic = x + y; 7 | bool relational = x > y; 8 | int bitwise = x | y; 9 | printf("%d %d %d", 10 | arithmetic, 11 | relational, 12 | bitwise); 13 | } 14 | int main(void) { 15 | foo(1, 3); 16 | return 0; 17 | } 18 | ``` 19 | 20 | * 逻辑运算符 - 0x1: 21 | ```c 22 | #include 23 | #include 24 | void foo(int x, int y) { 25 | bool logical = x && y; 26 | printf("%d", logical); 27 | } 28 | int main(void) { 29 | foo(1, 3); 30 | return 0; 31 | } 32 | ``` 33 | 34 | * 成员访问运算符 - 0x1: 35 | ```c 36 | #include 37 | void foo(void) { 38 | int n = 10; 39 | int* n_ptr = &n; 40 | int m = *n_ptr; 41 | printf("%d %p %d", n, n_ptr, m); 42 | } 43 | int main(void) { 44 | foo(); 45 | return 0; 46 | } 47 | ``` 48 | 49 | * 其他运算符 - 0x1: 50 | ```c 51 | #include 52 | #include 53 | void foo(int x, int y) { 54 | size_t n = sizeof(int); 55 | short f = (short) n; 56 | printf("%zd %d", n, f); 57 | } 58 | int main(void) { 59 | foo(1, 3); 60 | return 0; 61 | } 62 | ``` 63 | -------------------------------------------------------------------------------- /04|控制逻辑:表达式和语句是如何协调程序运行的?.md: -------------------------------------------------------------------------------- 1 | * 表达式 - 0x1: 2 | ```c 3 | int foo(void) { 4 | return (1 + 2) * 3 + 4 / 5; 5 | } 6 | ``` 7 | 8 | * 语句 - 0x1: 9 | ```c 10 | int foo(int x, int y) { // 复合语句; 11 | int sum = x + y; // 表达式语句; 12 | if (sum < 0) { // 复合语句; 13 | sum = -sum; // 表达式语句; 14 | } 15 | return sum; 16 | } 17 | ``` 18 | 19 | * 语句 - 0x2: 20 | ```c 21 | int foo(int v) { 22 | if (v == 10 || v == 20) { 23 | return 1; 24 | } else if (v == 30 || v == 40) { 25 | return 2; 26 | } else if (v == 50 || v == 60) { 27 | return 3; 28 | } else { 29 | return 4; 30 | } 31 | } 32 | ``` 33 | 34 | * 语句 - 0x3: 35 | ```c 36 | int foo(int v) { 37 | switch(v) { 38 | case 10: 39 | case 20: { 40 | return 1; 41 | break; 42 | } 43 | case 30: 44 | case 40: { 45 | return 2; 46 | break; 47 | } 48 | case 50: 49 | case 60: { 50 | return 3; 51 | break; 52 | } 53 | default: return 4; 54 | } 55 | } 56 | ``` 57 | 58 | * 语句 - 0x4: 59 | ```c 60 | #include 61 | int foo(int v) { 62 | do { 63 | printf("%d", v); 64 | } while(v--); 65 | } 66 | ``` 67 | -------------------------------------------------------------------------------- /05|代码封装(上):函数是如何被调用的?.md: -------------------------------------------------------------------------------- 1 | * 快速回顾 C 语言中函数的使用方式 - 0x1: 2 | ```c 3 | #include 4 | #include 5 | typedef struct { 6 | int x; 7 | int y; 8 | } Point; 9 | int foo(int x, int y, Point* p, int(handler)(int)) { 10 | return handler(x + y + p->x + p->y); 11 | } 12 | int handler(int n) { 13 | return sqrt(n); 14 | } 15 | int main(void) { 16 | int x = 2; 17 | int y = 3; 18 | Point p = { .x = 10, .y = 10 }; 19 | printf("%d", foo(x, y, &p, handler)); // 5. 20 | return 0; 21 | } 22 | ``` 23 | 24 | * C 函数的调用约定 - 0x1: 25 | ```c 26 | #include 27 | int bar() { 28 | return 10; 29 | } 30 | int foo(int a, int b, int c, int d, int e, int f, int g, int h) { 31 | int n = 10; 32 | return n + bar(); 33 | } 34 | int main(void) { 35 | int x = 1; 36 | int y = 2; 37 | printf("%d", foo(x, y, 3, 4, 5, 6, 7, 8)); 38 | return 0; 39 | } 40 | ``` 41 | -------------------------------------------------------------------------------- /06|代码封装(下):函数是如何被调用的?.md: -------------------------------------------------------------------------------- 1 | * 编写不依赖于参数求值顺序的函数 - 0x1: 2 | ```c 3 | #include 4 | int main(void) { 5 | int n = 1; 6 | printf("%d %d %d", n++, n++, n++); 7 | return 0; 8 | } 9 | ``` 10 | 11 | * 尾递归调用优化 - 0x1: 12 | ```c 13 | int factorial(int num) { 14 | if (num == 1 || num == 0) 15 | return 1; 16 | return num * factorial(num - 1); 17 | } 18 | ``` 19 | 20 | * 尾递归调用优化 - 0x2: 21 | ```c 22 | int factorial(int n, int acc) { 23 | if (n == 0) { 24 | return acc; 25 | } else { 26 | return factorial(n - 1, acc * n); 27 | } 28 | } 29 | ``` 30 | 31 | * 废弃的 K&R 函数声明 - 0x1: 32 | ```c 33 | #include 34 | int add(); 35 | int main(void) { 36 | printf("%d", add(1)); // ? 37 | return 0; 38 | } 39 | int add(int x, int y) { 40 | return x + y; 41 | } 42 | ``` 43 | 44 | * 废弃的 K&R 函数声明 - 0x2: 45 | ```c 46 | #include 47 | int add(int x, int y); 48 | int main(void) { 49 | printf("%d", add(1)); // compiling error! 50 | return 0; 51 | } 52 | int add(int x, int y) { 53 | return x + y; 54 | } 55 | ``` 56 | -------------------------------------------------------------------------------- /07|整合数据:枚举、结构与联合是如何实现的?.md: -------------------------------------------------------------------------------- 1 | * 枚举 - 0x1: 2 | ```c 3 | #include 4 | #define typename(x) _Generic((x), \ 5 | int: "int", \ 6 | default: "unknown") 7 | typedef enum { 8 | Mon, Tue, Wed, Thur, Fri, 9 | } Weekday; 10 | void foo(Weekday wd) { 11 | if (wd == Mon) { 12 | printf("The value of Mon is: %d\n", Mon); 13 | printf("The type of Mon is: %s", typename(Mon)); 14 | } 15 | } 16 | int main(void) { 17 | foo(Mon); 18 | return 0; 19 | } 20 | ``` 21 | 22 | * 结构 - 0x1: 23 | ```c 24 | #include 25 | typedef struct { 26 | char *p; 27 | char c; 28 | long x; 29 | } S; 30 | int main(void) { 31 | char c = 'a'; 32 | S s = { &c, 'b', 10 }; 33 | printf("%p\n%c\n%ld\n", s.p, s.c, s.x); 34 | printf("The size of S is: %zd bytes", sizeof(S)); 35 | return 0; 36 | } 37 | ``` 38 | 39 | * 联合 - 0x1: 40 | ```c 41 | #include 42 | typedef enum { INT, CHAR } Type; 43 | typedef struct { 44 | Type type; 45 | union { 46 | int i; 47 | char c; 48 | }; 49 | } S; 50 | void foo(S* s) { 51 | if (s -> type == CHAR) { 52 | printf("%c", s->c); 53 | } else { 54 | printf("%d", s->i); 55 | } 56 | } 57 | int main(void) { 58 | S s = { .type = CHAR, .c = 'a' }; 59 | foo(&s); 60 | return 0; 61 | } 62 | ``` 63 | -------------------------------------------------------------------------------- /08|操控资源:指针是如何灵活使用内存的?.md: -------------------------------------------------------------------------------- 1 | * 指针的基本使用 - 0x1: 2 | ```c 3 | #include 4 | int main(void) { 5 | int n = 10; 6 | const int* const npA = &n; 7 | int* npB = &n; 8 | *npB = 20; 9 | printf("The value is: %d\n", n); 10 | printf("Are they the same: %d", npA == npB); 11 | return 0; 12 | } 13 | ``` 14 | 15 | * 指针与数组 - 0x1: 16 | ```c 17 | #include 18 | int sum(int arr[], size_t len) { 19 | int total = 0; 20 | for (; len > 0; len--) 21 | total += *(arr + len - 1); 22 | return total; 23 | } 24 | int main(void) { 25 | int arr[] = { 1, 2, 3, 4 }; 26 | printf("%d", sum(arr, sizeof(arr) / sizeof(int))); 27 | return 0; 28 | } 29 | ``` 30 | 31 | * 指针的其他运算 - 0x1: 32 | ```c 33 | #include 34 | int main(void) { 35 | int arr[][3] = { 36 | { 1, 2, 3 }, 37 | { 4, 5, 6 } }; 38 | printf("%d\n", **(arr + 1)); // 4. 39 | printf("%d\n", *(*arr + 2)); // 3. 40 | return 0; 41 | } 42 | ``` 43 | 44 | * 堆内存指针 - 0x1: 45 | ```c 46 | #include 47 | #include 48 | #include 49 | #define N 5 50 | int main(void) { 51 | int arr[] = { 1, 2, 3, 4, 5 }; 52 | // 分配用于存放 N 个整数的堆内存; 53 | int* p = (int*) malloc(sizeof(int) * N); 54 | // 将数组 arr 中的元素复制到分配的堆内存中; 55 | memcpy(p, arr, sizeof(int) * N); 56 | for (int i = 0; i < N; ++i) { 57 | // 通过指针遍历堆空间中的数据; 58 | printf("%d\n", *(p + i)); 59 | } 60 | // 释放先前分配的堆空间,让操作系统可以回收内存; 61 | free(p); 62 | return 0; 63 | } 64 | ``` 65 | -------------------------------------------------------------------------------- /09|编译准备:预处理器是怎样处理程序代码的?.md: -------------------------------------------------------------------------------- 1 | * 预处理是怎样进行的? - 0x1: 2 | ```c 3 | #pragma GCC warning "Just FYI!" 4 | #include 5 | #define PI 3.14 6 | #define SQUARE(x) (x * x) 7 | int main(void) { 8 | #if defined PI 9 | // Some specific calculations. 10 | const double area = SQUARE(5) * PI; 11 | const bool isAreaGT100 = area > 100.0; 12 | #endif 13 | return 0; 14 | } 15 | ``` 16 | 17 | * 定义宏函数时的常用技巧 - 0x1: 18 | ```c 19 | #include 20 | #define FOO(x) 1 + x * x 21 | int main(void) { 22 | printf("%d", 3 * FOO(2)); 23 | return 0; 24 | } 25 | ``` 26 | 27 | * 定义宏函数时的常用技巧 - 0x2: 28 | ```c 29 | #include 30 | #define FOO(x) (1 + x * x) 31 | int main(void) { 32 | printf("%d", FOO(1 + 2)); 33 | return 0; 34 | } 35 | ``` 36 | 37 | * 定义宏函数时的常用技巧 - 0x3: 38 | ```c 39 | #include 40 | #define FOO(x) (1 + (x) * (x)) 41 | int main(void) { 42 | int i = 1; 43 | printf("%d", FOO(++i)); 44 | return 0; 45 | } 46 | ``` 47 | 48 | * 定义宏函数时的常用技巧 - 0x4: 49 | ```c 50 | #include 51 | #define SAY() printf("Hello, "); printf("world!") 52 | int main(void) { 53 | int input; 54 | scanf("%d", &input); 55 | if (input > 0) 56 | SAY(); 57 | return 0; 58 | } 59 | ``` 60 | 61 | * 定义宏函数时的常用技巧 - 0x5: 62 | ```c 63 | #include 64 | #define SAY() \ 65 | do { printf("Hello, "); printf("world!"); } while(0) 66 | int main(void) { 67 | int input; 68 | scanf("%d", &input); 69 | if (input > 0) 70 | SAY(); 71 | return 0; 72 | } 73 | ``` 74 | -------------------------------------------------------------------------------- /10 | 标准库:字符、字符串处理与数学计算.md: -------------------------------------------------------------------------------- 1 | * C 标准库中的字符、字符串处理 - 统计字符串长度: 2 | ```c 3 | #include 4 | #include 5 | int main(void) { 6 | const char str[10] = "Hi"; 7 | printf("%zu\n", strlen(str)); // 2. 8 | } 9 | ``` 10 | 11 | * C 标准库中的字符、字符串处理 - 拼接字符串: 12 | ```c 13 | #include 14 | #include 15 | #define STRLEN 14 16 | int main(void) { 17 | char strA[STRLEN] = "Hello,"; 18 | char strB[] = " world!"; 19 | strncat(strA, strB, STRLEN - strlen(strA) - 1); 20 | printf("%s\n", strA); 21 | } 22 | ``` 23 | 24 | * C 标准库中的字符、字符串处理 - 拷贝字符串: 25 | ```c 26 | #include 27 | #include 28 | int main(void) { 29 | char strA[] = "aaaaaa"; 30 | char strB[] = "bbbbbbb"; 31 | printf("%s\n", strncpy(strA, strB, strlen(strA))); // "bbbbbb". 32 | } 33 | ``` 34 | 35 | * C 标准库中的字符、字符串处理 - 格式化字符串: 36 | ```c 37 | #include 38 | #define LEN 128 39 | int main(void) { 40 | char dest[LEN]; 41 | const char strA[] = "Hello, "; 42 | sprintf(dest, "%sworld!", strA); 43 | printf("%s\n", dest); 44 | } 45 | ``` 46 | 47 | * C 标准库中的字符、字符串处理 - 字符的判断与转换: 48 | ```c 49 | #include 50 | #include 51 | int main(void) { 52 | char c = 'a'; 53 | printf("%d\n", isalnum(c)); // 1. 54 | printf("%d\n", isalpha(c)); // 1. 55 | printf("%d\n", isblank(c)); // 0. 56 | printf("%d\n", isdigit(c)); // 0. 57 | printf("%c\n", toupper(c)); // 'A'. 58 | } 59 | ``` 60 | -------------------------------------------------------------------------------- /11|标准库:深入理解标准 IO.md: -------------------------------------------------------------------------------- 1 | * C 快速回顾 IO 接口的使用方法 - 0x1: 2 | ```c 3 | #include 4 | int main(void) { 5 | printf("Enter some characters:\n"); 6 | FILE* fp = fopen("./temp.txt", "w+"); 7 | if (fp) { 8 | char ch; 9 | while (scanf("%c", &ch)) { 10 | if (ch == 'z') break; 11 | putc(ch, fp); 12 | } 13 | } else { 14 | perror("File open failed."); 15 | } 16 | fclose(fp); 17 | return 0; 18 | } 19 | ``` 20 | 21 | * IO 接口的不同级别 - 0x1: 22 | ```c 23 | #include 24 | #include 25 | int main(void) { 26 | const char str[] = "Enter some characters:\n"; 27 | write(STDOUT_FILENO, str, sizeof(str)); 28 | const int fd = open("./temp.txt", O_RDWR | O_CREAT); 29 | if (fd > 0) { 30 | char ch; 31 | while (read(STDIN_FILENO, &ch, 1)) { 32 | if (ch == 'z') break; 33 | write(fd, &ch, sizeof(ch)); 34 | } 35 | } else { 36 | const char errMsg[] = "File open failed."; 37 | write(STDERR_FILENO, errMsg, sizeof(errMsg)); 38 | } 39 | close(fd); 40 | return 0; 41 | } 42 | ``` 43 | 44 | * 用于低级 IO 接口的操作系统调用 - 0x1: 45 | ```c 46 | #include 47 | #include 48 | int main(void) { 49 | const char str[] = "Enter some characters:\n"; 50 | write(STDOUT_FILENO, str, sizeof(str)); 51 | const char* fileName = "./temp.txt"; 52 | // Call to `open` starts: 53 | // const int fd = open("./temp.txt", O_RDWR | O_CREAT); 54 | volatile int fd; 55 | asm("mov $2, %%rax\n\t" 56 | "mov %0, %%rdi\n\t" 57 | "mov $66, %%rsi\n\t" // 2 | 64 -> 66; 58 | "syscall\n\t" 59 | "mov %%rax, %1\n\t" 60 | : "=m" (fileName) 61 | : "m" (fd)); 62 | // Call ended. 63 | if (fd > 0) { 64 | char ch; 65 | while (read(STDIN_FILENO, &ch, 1)) { 66 | if (ch == 'z') break; 67 | write(fd, &ch, sizeof(ch)); 68 | } 69 | } else { 70 | const char errMsg[] = "File open failed."; 71 | write(STDERR_FILENO, errMsg, sizeof(errMsg)); 72 | } 73 | close(fd); 74 | return 0; 75 | } 76 | ``` 77 | 78 | -------------------------------------------------------------------------------- /12|标准库:非本地跳转与可变参数是怎样实现的?.md: -------------------------------------------------------------------------------- 1 | * 非本地跳转 - 本地跳转: 2 | ```c 3 | #include 4 | int main(void) { 5 | int n; 6 | head: 7 | scanf("%d", &n); 8 | if (n > 0) goto head; 9 | return 0; 10 | } 11 | ``` 12 | 13 | * 非本地跳转 - setjmp 与 longjmp 函数: 14 | ```c 15 | #include 16 | #include 17 | #include 18 | jmp_buf jb; 19 | noreturn void inspect(char val) { 20 | putchar(val); 21 | longjmp(jb, val); 22 | } 23 | int main(void) { 24 | volatile char c = 'A'; 25 | if (setjmp(jb) < 'J') 26 | inspect(c++); 27 | return 0; 28 | } 29 | ``` 30 | 31 | * 非本地跳转 - 自定义实现 - 0x1: 32 | ```c 33 | .global setjmp 34 | .intel_syntax noprefix 35 | setjmp: 36 | mov QWORD PTR [rdi], rbx 37 | mov QWORD PTR [rdi+0x8], rbp 38 | mov QWORD PTR [rdi+0x10], r12 39 | mov QWORD PTR [rdi+0x18], r13 40 | mov QWORD PTR [rdi+0x20], r14 41 | mov QWORD PTR [rdi+0x28], r15 42 | lea rdx, [rsp+0x8] 43 | mov QWORD PTR [rdi+0x30], rdx 44 | mov rdx, QWORD PTR [rsp] 45 | mov QWORD PTR [rdi+0x38], rdx 46 | xor eax, eax 47 | ret 48 | ``` 49 | 50 | * 非本地跳转 - 自定义实现 - 0x2: 51 | ```c 52 | .global longjmp 53 | .intel_syntax noprefix 54 | longjmp: 55 | xor eax, eax 56 | cmp esi, 0x1 57 | adc eax, esi 58 | mov rbx, QWORD PTR [rdi] 59 | mov rbp, QWORD PTR [rdi+0x8] 60 | mov r12, QWORD PTR [rdi+0x10] 61 | mov r13, QWORD PTR [rdi+0x18] 62 | mov r14, QWORD PTR [rdi+0x20] 63 | mov r15, QWORD PTR [rdi+0x28] 64 | mov rsp, QWORD PTR [rdi+0x30] 65 | jmp QWORD PTR [rdi+0x38] 66 | ``` 67 | 68 | * 非本地跳转 - 自定义实现 - 0x3: 69 | ```c 70 | #include 71 | #include 72 | // 定义 jmp_buf 类型; 73 | typedef long jmp_buf[8]; 74 | // 提供函数原型; 75 | int setjmp(jmp_buf); 76 | noreturn void longjmp(jmp_buf, int); 77 | // 原始 C 示例程序代码; 78 | jmp_buf jb; 79 | noreturn void inspect(char val) { 80 | putchar(val); 81 | longjmp(jb, val); 82 | } 83 | int main(void) { 84 | volatile char count = 'A'; 85 | if (setjmp(jb) < 'J') 86 | inspect(count++); 87 | return 0; 88 | } 89 | ``` 90 | 91 | * 可变参数函数 - 基本使用: 92 | ```c 93 | #include 94 | #include 95 | void print_sum(int count, ...) { 96 | int sum = 0; 97 | va_list ap; 98 | va_start(ap, count); 99 | for (int i = 0; i < count; ++i) 100 | sum += va_arg(ap, int); 101 | va_end(ap); 102 | printf("%d\n", sum); 103 | } 104 | int main(void) { 105 | print_sum(4, 1, 2, 3, 4); 106 | return 0; 107 | } 108 | ``` 109 | -------------------------------------------------------------------------------- /13|标准库:你需要了解的 C 并发编程基础知识有哪些?.md: -------------------------------------------------------------------------------- 1 | * 线程的基本控制 - 0x1: 2 | ```c 3 | #include 4 | #include 5 | int run(void *arg) { 6 | thrd_t id = thrd_current(); // 返回该函数运行所在线程的标识符; 7 | printf((const char*) arg, id); 8 | return thrd_success; 9 | } 10 | int main(void) { 11 | #ifndef __STDC_NO_THREADS__ 12 | thrd_t thread; 13 | int result; 14 | // 创建一个线程; 15 | thrd_create(&thread, run, "Hello C11 thread with id: %lu.\n"); 16 | if (thrd_join(thread, &result) == thrd_success) { 17 | // 等待其他线程退出; 18 | printf("Thread returns %d at the end.\n", result); 19 | } 20 | #endif 21 | return 0; 22 | } 23 | ``` 24 | 25 | * 数据竞争 - 0x1: 26 | ```c 27 | #include 28 | #include 29 | #define THREAD_COUNT 20 30 | #define THREAD_LOOP 100000000 31 | long counter = 0; // 全局变量,用来记录线程的累加值; 32 | int run(void* data) { 33 | for (int i = 0; i < THREAD_LOOP; i++) 34 | counter++; // 在线程中递增全局变量的值; 35 | printf("Thread %d terminates.\n", *((int*) data)); 36 | return thrd_success; 37 | } 38 | int main(void) { 39 | #ifndef __STDC_NO_THREADS__ 40 | int ids[THREAD_COUNT]; // 用于存放线程序号的数组; 41 | thrd_t threads[THREAD_COUNT]; 42 | for (int i = 0; i < THREAD_COUNT; i++) { 43 | ids[i] = i + 1; 44 | thrd_create(&threads[i], run, ids + i); // 创建 THREAD_COUNT 个线程; 45 | } 46 | for (int i = 0; i < THREAD_COUNT; i++) 47 | thrd_join(threads[i], NULL); // 让当前线程等待其他线程执行完毕; 48 | printf("Counter value is: %ld.\n", counter); // 输出 counter 变量最终结果; 49 | #endif 50 | return 0; 51 | } 52 | ``` 53 | 54 | * 竞态条件 - 0x1: 55 | ```c 56 | #include 57 | #include 58 | #include 59 | #include 60 | #include 61 | #include 62 | #define THREAD_COUNT 10 63 | atomic_int accountA = 100000000; // 转出账户初始金额; 64 | atomic_int accountB = 0; // 转入账户初始金额; 65 | int run(void* v) { 66 | int _amount = *((int*) v); // 获得当前线程的转移金额; 67 | for(;;) { 68 | // 首先判断转出账户金额是否足够,不够则直接退出; 69 | if (accountA < _amount) return thrd_error; 70 | atomic_fetch_add(&accountB, _amount); // 将金额累加到转入账户; 71 | atomic_fetch_sub(&accountA, _amount); // 将金额从转出账户中扣除; 72 | } 73 | } 74 | int main(void) { 75 | #if !defined(__STDC_NO_THREADS__) && !defined(__STDC_NO_ATOMICS__) 76 | thrd_t threads[THREAD_COUNT]; 77 | srand(time(NULL)); 78 | for (int i = 0; i < THREAD_COUNT; i++) { 79 | int amount = rand() % 50; // 为每一个线程生成一个随机转移金额; 80 | thrd_create(&threads[i], run, &amount); 81 | } 82 | for (int i = 0; i < THREAD_COUNT; i++) 83 | thrd_join(threads[i], NULL); 84 | printf("A: %d\nB: %d", accountA, accountB); 85 | #endif 86 | return 0; 87 | } 88 | ``` 89 | 90 | * 指令重排 - 0x1: 91 | ```c 92 | #include 93 | #include 94 | #include 95 | #if !defined(__STDC_NO_ATOMICS__) 96 | atomic_int x = 0, y = 0; 97 | #endif 98 | int run(void* v) { 99 | x = 10; 100 | y = 20; // !变量 y 的值可能被优先更新! 101 | } 102 | int observe(void* v) { 103 | while(y != 20) ; // 忙等待; 104 | printf("%d", x); // 只在 x 被更新后打印; 105 | } 106 | int main(void) { 107 | #if !defined(__STDC_NO_THREADS__) 108 | thrd_t threadA, threadB; 109 | thrd_create(&threadA, run, NULL); 110 | thrd_create(&threadB, observe, NULL); 111 | thrd_join(threadA, NULL); 112 | thrd_join(threadB, NULL); 113 | #endif 114 | return 0; 115 | } 116 | ``` 117 | -------------------------------------------------------------------------------- /14|标准库:如何使用互斥量等技术协调线程运行?.md: -------------------------------------------------------------------------------- 1 | * 使用互斥量 - 0x1: 2 | ```c 3 | #include 4 | #include 5 | #define THREAD_COUNT 10 6 | #define THREAD_LOOP 100000000 7 | mtx_t mutex; 8 | long counter = 0; 9 | int run(void* data) { 10 | for (int i = 0; i < THREAD_LOOP; i++) { 11 | mtx_lock(&mutex); // 对互斥量加锁, 12 | counter++; 13 | mtx_unlock(&mutex); // 释放一个互斥量; 14 | } 15 | printf("Thread %d terminates.\n", *((int*) data)); 16 | return thrd_success; 17 | } 18 | int main(void) { 19 | #ifndef __STDC_NO_THREADS__ 20 | int ids[THREAD_COUNT]; 21 | mtx_init(&mutex, mtx_plain); // 创建一个简单、非递归的互斥量对象; 22 | thrd_t threads[THREAD_COUNT]; 23 | for (int i = 0; i < THREAD_COUNT; i++) { 24 | ids[i] = i + 1; 25 | thrd_create(&threads[i], run, ids + i); 26 | } 27 | for (int i = 0; i < THREAD_COUNT; i++) 28 | thrd_join(threads[i], NULL); 29 | printf("Counter value is: %ld.\n", counter); 30 | mtx_destroy(&mutex); // 销毁一个互斥量对象; 31 | #endif 32 | return 0; 33 | } 34 | ``` 35 | 36 | * 使用原子操作 - 0x1: 37 | ```c 38 | #include 39 | #include 40 | #include 41 | #define THREAD_COUNT 10 42 | #define THREAD_LOOP 100000000 43 | #if !defined(__STDC_NO_ATOMICS__) 44 | _Atomic long counter = 0; // 定义一个原子类型全局变量,用来记录线程的累加值; 45 | #endif 46 | int run(void* data) { 47 | for (int i = 0; i < THREAD_LOOP; i++) 48 | atomic_fetch_add_explicit(&counter, 1, memory_order_relaxed); // 使用原子加法操作; 49 | printf("Thread %d terminates.\n", *((int*) data)); 50 | return thrd_success; 51 | } 52 | int main(void) { 53 | #if !defined(__STDC_NO_THREADS__) || !defined(__STDC_NO_ATOMICS__) 54 | int ids[THREAD_COUNT]; 55 | thrd_t threads[THREAD_COUNT]; 56 | for (int i = 0; i < THREAD_COUNT; i++) { 57 | ids[i] = i + 1; 58 | thrd_create(&threads[i], run, ids + i); 59 | } 60 | for (int i = 0; i < THREAD_COUNT; i++) 61 | thrd_join(threads[i], NULL); 62 | printf("Counter value is: %ld.\n", counter); 63 | #endif 64 | return 0; 65 | } 66 | ``` 67 | 68 | * 使用原子操作 - 0x2: 69 | ```c 70 | #include 71 | #include 72 | #include 73 | #if !defined(__STDC_NO_ATOMICS__) 74 | atomic_int x = 0, y = 0; 75 | #endif 76 | int run(void* v) { 77 | atomic_store_explicit(&x, 10, memory_order_relaxed); 78 | atomic_store_explicit(&y, 20, memory_order_release); 79 | } 80 | int observe(void* v) { 81 | while(atomic_load_explicit(&y, memory_order_acquire) != 20); 82 | printf("%d", atomic_load_explicit(&x, memory_order_relaxed)); 83 | } 84 | int main(void) { 85 | #if !defined(__STDC_NO_THREADS__) || !defined(__STDC_NO_ATOMICS__) 86 | thrd_t threadA, threadB; 87 | thrd_create(&threadA, run, NULL); 88 | thrd_create(&threadB, observe, NULL); 89 | thrd_join(threadA, NULL); 90 | thrd_join(threadB, NULL); 91 | #endif 92 | return 0; 93 | } 94 | ``` 95 | 96 | * 使用条件变量 - 0x1: 97 | ```c 98 | include 99 | #include 100 | mtx_t mutex; 101 | cnd_t cond; // 定义一个条件变量; 102 | int done = 0; 103 | int run(void* data) { 104 | mtx_lock(&mutex); 105 | done = 1; 106 | cnd_signal(&cond); // 通知等待中的线程; 107 | mtx_unlock(&mutex); 108 | return thrd_success; 109 | } 110 | int main(void) { 111 | #ifndef __STDC_NO_THREADS__ 112 | mtx_init(&mutex, mtx_plain); 113 | cnd_init(&cond); // 初始化条件变量; 114 | thrd_t thread; 115 | thrd_create(&thread, run, NULL); 116 | mtx_lock(&mutex); 117 | while (done == 0) { 118 | cnd_wait(&cond, &mutex); // 让当前线程进入等待队列; 119 | } 120 | mtx_unlock(&mutex); 121 | printf("The value of done is: %d", done); 122 | mtx_destroy(&mutex); 123 | cnd_destroy(&cond); // 销毁条件变量; 124 | #endif 125 | return 0; 126 | } 127 | ``` 128 | 129 | * 使用线程本地变量 - 0x1: 130 | ```c 131 | #include 132 | #include 133 | #include 134 | #define THREAD_COUNT 10 135 | #define THREAD_LOOP 10000 136 | _Thread_local int counter = 0; // 定义线程本地变量; 137 | int run(void *data) { 138 | for (int i = 0; i < THREAD_LOOP; ++i) 139 | counter += 1; // 更新当前线程所属的 counter 变量值; 140 | return counter; 141 | } 142 | int main(int argc, char const *argv[]) { 143 | thrd_t threads[THREAD_COUNT]; 144 | int sum = 0, result = 0; 145 | for (int i = 0; i < THREAD_COUNT; ++i) 146 | thrd_create(&threads[i], run, NULL); 147 | for (int i = 0; i < THREAD_COUNT; ++i) { 148 | thrd_join(threads[i], &result); 149 | sum += result; // 累加每个线程的计算值; 150 | } 151 | printf("The value of count is %d.\n", sum); 152 | return 0; 153 | } 154 | ``` -------------------------------------------------------------------------------- /15|标准库:信号与操作系统软中断有什么关系?.md: -------------------------------------------------------------------------------- 1 | * 在 C 代码中与信号交互 - 0x1: 2 | ```c 3 | #include 4 | #include 5 | #include 6 | void sigHandler(int sig) { 7 | printf("Signal %d catched!\n", sig); 8 | exit(sig); 9 | } 10 | int main(void) { 11 | signal(SIGFPE, sigHandler); 12 | int x = 10; 13 | int y = 0; 14 | printf("%d", x / y); 15 | } 16 | ``` 17 | 18 | * 在 C 代码中与信号交互 - 0x2: 19 | ```c 20 | #include 21 | #include 22 | int main(void) { 23 | signal(SIGTERM, SIG_IGN); // 忽略信号 SIGTERM; 24 | raise(SIGTERM); // 向当前程序发送 SIGTERM 信号; 25 | printf("Reachable!\n"); // Reachable code! 26 | return 0; 27 | } 28 | ``` 29 | 30 | * 可重入函数 - 0x1: 31 | ```c 32 | #include 33 | #include 34 | #include 35 | #define BUF_SIZE 16 // 全局静态数组大小; 36 | #define FORMAT_NUM_(N) " $"#N 37 | #define FORMAT_NUM(N) FORMAT_NUM_(N) 38 | #define RAISE_EXP_false_ASM() 39 | // 调用 raise 函数向当前程序发送信号; 40 | #define RAISE_EXP_true_ASM() \ 41 | "movl $4, %%edi\n\t" \ 42 | "call raise\n\t" 43 | // 内联汇编实现; 44 | #define INLINE_ASM(ID, HAS_EXP) \ 45 | "mov %0, %%r8\n\t" /* 复制传入的字符串数据到全局静态数组 */ \ 46 | "testq %%rsi, %%rsi\n\t" \ 47 | "je .L1" #ID "\n\t" \ 48 | "xorl %%eax, %%eax\n\t" \ 49 | ".L3" #ID ":\n\t" \ 50 | "movzbl (%%rdi,%%rax), %%ecx\n\t" \ 51 | "movb %%cl, (%%r8,%%rax)\n\t" \ 52 | "addq $1, %%rax\n\t" \ 53 | "cmpq %%rsi, %%rax\n\t" \ 54 | "jne .L3" #ID "\n\t" \ 55 | ".L1" #ID ":\n\t" \ 56 | RAISE_EXP_##HAS_EXP##_ASM() /* 选择性调用 raise 函数 */ \ 57 | "mov $1, %%rax\n\t" \ 58 | "mov $1, %%rdi\n\t" \ 59 | "mov %0, %%rsi\n\t" \ 60 | "mov" FORMAT_NUM(BUF_SIZE) ", %%rdx\n\t" \ 61 | "syscall\n\t" /* 触发系统调用,打印内容 */ 62 | 63 | static char buf[BUF_SIZE]; // 用于保存字符的全局静态数组; 64 | void print_with_exp(const char* str, size_t len) { // 会引起信号中断的版本; 65 | asm(INLINE_ASM(a, true) :: "g" (buf)); 66 | } 67 | void print_normal(const char* str, size_t len) { // 正常的版本; 68 | asm(INLINE_ASM(b, false) :: "g" (buf)); 69 | } 70 | void sigHandler(int sig) { 71 | const char* str = "Hello"; 72 | print_normal(str, strlen(str)); 73 | } 74 | int main(void) { 75 | signal(SIGILL, sigHandler); 76 | const char* str = ", world!"; 77 | print_with_exp(str, strlen(str)); 78 | return 0; 79 | } 80 | ``` 81 | 82 | * 可重入函数 - 0x2: 83 | ```c 84 | #include 85 | #include 86 | #include 87 | #include 88 | volatile sig_atomic_t sig = 0; 89 | void sigHandler(int signal) { 90 | sig = signal; 91 | } 92 | int main(void) { 93 | signal(SIGINT, sigHandler); 94 | int counter = 0; // 计数器变量; 95 | while(1) { 96 | switch (sig) { // 信号筛选与处理; 97 | case SIGINT: { 98 | printf("SignalValue: %d", sig); 99 | /* 异常处理的主要逻辑 */ 100 | exit(SIGINT); 101 | } 102 | } 103 | if (counter == 5) raise(SIGINT); 104 | printf("Counter: %d\n", counter++); 105 | sleep(1); 106 | } 107 | return 0; 108 | } 109 | ``` 110 | -------------------------------------------------------------------------------- /16|标准库:日期、时间与实用函数.md: -------------------------------------------------------------------------------- 1 | * C 日历时间 - 0x1: 2 | ```c 3 | #include 4 | #include 5 | int main(void) { 6 | time_t currTime = time(NULL); 7 | if(currTime != (time_t)(-1)) 8 | printf("The current timestamp is: %ld(s)", currTime); 9 | return 0; 10 | } 11 | ``` 12 | 13 | * C 日历时间 - 0x2: 14 | ```c 15 | #include 16 | #include 17 | int main(void) { 18 | time_t currTime = time(NULL); 19 | if(currTime != (time_t)(-1)) { 20 | char buff[64]; 21 | struct tm* tm = localtime(&currTime); 22 | if (strftime(buff, sizeof buff, "%A %c", tm)) 23 | printf("The current local time is: %s", buff); // "The current local time is: Saturday Sat Jan 8 16:30:49 2022". 24 | } 25 | return 0; 26 | } 27 | ``` 28 | 29 | * C 处理器时间 - 0x1: 30 | ```c 31 | #include 32 | #include 33 | int main(void) { 34 | clock_t startTime = clock(); 35 | for(int i = 0; i < 10000000; i++) {} 36 | clock_t endTime = clock(); 37 | printf("Consumed CPU time is:%fs\n", 38 | (double)(endTime - startTime) / CLOCKS_PER_SEC); 39 | return 0; 40 | } 41 | ``` 42 | 43 | * C 处理器时间 - 0x2: 44 | ```c 45 | #include 46 | #include 47 | #include 48 | #include 49 | typedef struct timespec ts_t; 50 | int run(void* data) { // 模拟的耗时任务; 51 | volatile double d = 0; 52 | for (int n = 0; n < 10000; ++n) 53 | for (int m = 0; m < 10000; ++m) 54 | d += d * n * m; 55 | return 0; 56 | } 57 | int main(void) { 58 | // 首次记录日历时间与处理器时间; 59 | ts_t ts1; 60 | timespec_get(&ts1, TIME_UTC); 61 | clock_t t1 = clock(); 62 | // 创建两个线程,做一些耗时任务; 63 | thrd_t thr1, thr2; 64 | thrd_create(&thr1, run, NULL); 65 | thrd_create(&thr2, run, NULL); 66 | thrd_join(thr1, NULL); 67 | thrd_join(thr2, NULL); 68 | // 再次记录日历时间与处理器时间; 69 | ts_t ts2; 70 | timespec_get(&ts2, TIME_UTC); 71 | clock_t t2 = clock(); 72 | // 分别计算和打印处理器时间与墙上时钟时间耗时; 73 | printf("CPU time used (per clock()): %.2f ms\n", 1000.0 * (t2 - t1) / CLOCKS_PER_SEC); 74 | printf("Wall time passed: %.2f ms\n", 75 | 1000.0 * ts2.tv_sec + 1e-6 * ts2.tv_nsec - (1000.0 * ts1.tv_sec + 1e-6 * ts1.tv_nsec)); 76 | return 0; 77 | } 78 | ``` 79 | 80 | * 字符串到数值的转换 - 0x1: 81 | ```c 82 | #include 83 | #include 84 | #include 85 | int main(void) { 86 | // 一次性字符串到数值转换; 87 | const char* strA = "1.0"; 88 | printf("%f\n", atof(strA)); 89 | // 带溢出检查的转换函数,执行后会保存不能被转换部分的地址; 90 | const char* strB = "200000000000000000000000000000.0"; 91 | char* end; 92 | double num = strtol(strB, &end, 10); 93 | if (errno == ERANGE) { // 判断转换结果是否发生溢出; 94 | printf("Range error, got: "); 95 | errno = 0; 96 | } 97 | printf("%f\n", num); 98 | return 0; 99 | } 100 | ``` 101 | 102 | 103 | * 生成随机数 - 0x1: 104 | ```c 105 | #include 106 | #include 107 | #include 108 | int main (void) { 109 | srand(time(NULL)); // 初始化随机数种子; 110 | while (getchar() == '\n') 111 | printf("%d", rand() % 10); // 生成并打印 0-9 的随机数; 112 | return 0; 113 | } 114 | ``` 115 | 116 | * 进程管理 - 0x1: 117 | ```c 118 | #include 119 | #include 120 | void exitHandler() { 121 | printf("%s\n", getenv("PATH")); 122 | } 123 | int main(void) { 124 | if (!atexit(exitHandler)) { 125 | exit(EXIT_SUCCESS); 126 | } 127 | return 0; 128 | } 129 | ``` 130 | -------------------------------------------------------------------------------- /17|标准库:断言、错误处理与对齐.md: -------------------------------------------------------------------------------- 1 | * 断言 - 0x1: 2 | ```c 3 | #include 4 | double sqrt(double x) { 5 | // 检查函数使用时传入的参数; 6 | assert(x > 0.0); 7 | // ... 8 | } 9 | int main(void) { 10 | // 检查程序的编译要求; 11 | static_assert(sizeof(int) >= 4, 12 | "Integer should have at least 4 bytes length."); 13 | // ... 14 | return 0; 15 | } 16 | ``` 17 | 18 | * 错误处理 - 0x1: 19 | ```c 20 | #include 21 | #include 22 | #include 23 | #include 24 | int main(void) { 25 | sqrt(-1); 26 | fprintf(stderr, "%s\n", strerror(errno)); // "Numerical argument out of domain". 27 | return 0; 28 | } 29 | ``` 30 | 31 | * 错误处理 - 0x2: 32 | ```c 33 | #include 34 | #include 35 | #include 36 | #include 37 | int run(void* data) { 38 | log(0.0); 39 | perror("Run"); // "Run: Numerical result out of range". 40 | return thrd_success; 41 | } 42 | int main(void) { 43 | #ifndef __STDC_NO_THREADS__ 44 | thrd_t thread; 45 | thrd_create(&thread, run, NULL); 46 | thrd_join(thread, NULL); 47 | perror("Main"); // "Main: Success". 48 | #endif 49 | return 0; 50 | } 51 | ``` 52 | 53 | * 自定义数据对齐 - 0x1: 54 | ```c 55 | #include 56 | #include 57 | int main(void) { 58 | #if __alignas_is_defined == 1 && __alignof_is_defined == 1 59 | alignas(1024) int n = 1; 60 | printf("The alignment of n is %zu\n", alignof(n)); // "The alignment of n is 1024". 61 | printf("The address of n is: %p\n", &n); // "The address of n is: 0x7ffe80658c00". 62 | #endif 63 | return 0; 64 | } 65 | ``` 66 | -------------------------------------------------------------------------------- /18|极致优化(上):如何实现高性能的 C 程序?.md: -------------------------------------------------------------------------------- 1 | * 技巧一:利用高速缓存 - 0x1: 2 | ```c 3 | #define M 128 4 | #define N 64 5 | int sum(int a[M][N]) { 6 | int i, j, sum = 0; 7 | for (j = 0; j < N; ++j) { 8 | for (i = 0; i < M; ++i) { 9 | sum += a[i][j]; 10 | } 11 | } 12 | return sum; 13 | } 14 | ``` 15 | 16 | * 技巧二:代码内联 - 0x1: 17 | ```c 18 | #include 19 | static inline int foo() { 20 | return 10; 21 | } 22 | int main(void) { 23 | int v = foo(); 24 | printf("Output is: %d\n", v); 25 | return 0; 26 | } 27 | ``` 28 | 29 | * 技巧三:restrict 关键字 - 0x1: 30 | ```c 31 | #include 32 | void foo(int* x, int* y, int* restrict z) { 33 | *x += *z; 34 | *y += *z; 35 | } 36 | int main(void) { 37 | int x = 10, y = 20, z = 30; 38 | foo(&x, &y, &z); 39 | printf("%d %d %d", x, y, z); 40 | return 0; 41 | } 42 | ``` 43 | 44 | * 技巧四:消除不必要的内存引用 - 0x1: 45 | ```c 46 | #define LEN 1024 47 | int data[LEN] = { ... }; 48 | int foo(int* dest) { 49 | *dest = 1; 50 | for (int i = 0; i < LEN; i++) { 51 | *dest = *dest * data[i]; 52 | } 53 | } 54 | ``` 55 | 56 | * 技巧四:消除不必要的内存引用 - 0x2: 57 | ```c 58 | #define LEN 3 59 | int data[LEN] = { 1,2,4 }; 60 | int foo(int* dest) { 61 | register int acc = 1; 62 | for (int i = 0; i < LEN; i++) { 63 | acc = acc * data[i]; 64 | } 65 | *dest = acc; 66 | } 67 | ``` 68 | -------------------------------------------------------------------------------- /19|极致优化(下):如何实现高性能的 C 程序?.md: -------------------------------------------------------------------------------- 1 | * 技巧五:循环展开(Loop Unrolling) - 0x1: 2 | ```c 3 | #define LEN 4096 4 | int data[LEN] = { ... }; 5 | int foo(void) { 6 | int acc = 1; 7 | for (int i = 0; i < LEN; ++i) { 8 | acc = acc * data[i]; 9 | } 10 | return acc; 11 | } 12 | ``` 13 | 14 | * 技巧五:循环展开(Loop Unrolling) - 0x2: 15 | ```c 16 | #define LEN 4096 17 | int data[LEN] = { ... }; 18 | int foo(void) { 19 | int limit = LEN - 1; 20 | int i; 21 | int acc0 = 1; 22 | int acc1 = 1; 23 | for (i = 0; i < limit; i += 2) { // 2x2 loop unrolling. 24 | acc0 = acc0 * data[i]; 25 | acc1 = acc1 * data[i + 1]; 26 | } 27 | for (; i < LEN; ++i) { // Finish any remaining elements. 28 | acc0 = acc0 * data[i]; 29 | } 30 | return acc0 * acc1; 31 | } 32 | ``` 33 | 34 | * 技巧六:优先使用条件传送指令 - 0x1: 35 | ```c 36 | #define LEN 1024 37 | void foo(int* x, int* y) { 38 | int i; 39 | for (i = 0; i < LEN; i++) { 40 | if (x[i] > y[i]) { 41 | int t = x[i]; 42 | x[i] = y[i]; 43 | y[i] = t; 44 | } 45 | } 46 | } 47 | ``` 48 | 49 | * 技巧六:优先使用条件传送指令 - 0x2: 50 | ```c 51 | #include 52 | #define LEN 16 53 | void foo(int* x, int* y) { 54 | int i; 55 | for (i = 0; i < LEN; i++) { 56 | int min = x[i] < y[i] ? x[i] : y[i]; 57 | int max = x[i] < y[i] ? y[i] : x[i]; 58 | x[i] = min; 59 | y[i] = max; 60 | } 61 | } 62 | ``` 63 | -------------------------------------------------------------------------------- /22|生产加速:如何使用结构化编译加速 C 项目构建?/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | # 设置项目名称; 3 | project(Test) 4 | # 设置二进制目标文件名称; 5 | set(TARGET_FILE "main") 6 | # 添加源文件目录; 7 | aux_source_directory(./src DIR_SRCS) 8 | # 设置二进制目标文件的依赖; 9 | add_executable(${TARGET_FILE} ${DIR_SRCS}) 10 | # 设置头文件查找目录; 11 | target_include_directories(${TARGET_FILE} PUBLIC "${PROJECT_SOURCE_DIR}/include") 12 | # 设置需要链接的库; 13 | target_link_libraries(${TARGET_FILE} PUBLIC m) 14 | -------------------------------------------------------------------------------- /22|生产加速:如何使用结构化编译加速 C 项目构建?/Makefile: -------------------------------------------------------------------------------- 1 | # 用于控制编译细节的自定义宏; 2 | CC = gcc 3 | CFLAGS = -I./include 4 | LDFLAGS = -lm 5 | TARGET_FILE = bin/main 6 | 7 | # 描述各个目标的详细编译步骤; 8 | $(TARGET_FILE): $(patsubst src/%.c,src/%.o,$(wildcard src/*.c)) 9 | $(CC) $^ $(LDFLAGS) -o $@ 10 | 11 | src/%.o: src/%.c include/%.h 12 | $(CC) $< $(CFLAGS) -c -o $@ -------------------------------------------------------------------------------- /22|生产加速:如何使用结构化编译加速 C 项目构建?/bin/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Becavalier/geektime-c/46cfc1b8281d343cbca083412b4733e043bf890a/22|生产加速:如何使用结构化编译加速 C 项目构建?/bin/.gitkeep -------------------------------------------------------------------------------- /22|生产加速:如何使用结构化编译加速 C 项目构建?/build/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Becavalier/geektime-c/46cfc1b8281d343cbca083412b4733e043bf890a/22|生产加速:如何使用结构化编译加速 C 项目构建?/build/.gitkeep -------------------------------------------------------------------------------- /22|生产加速:如何使用结构化编译加速 C 项目构建?/include/mod.h: -------------------------------------------------------------------------------- 1 | int fib(int); 2 | -------------------------------------------------------------------------------- /22|生产加速:如何使用结构化编译加速 C 项目构建?/src/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "mod.h" 4 | int main(void) { 5 | printf("%f\n", sqrt(fib(5))); 6 | return 0; 7 | } 8 | -------------------------------------------------------------------------------- /22|生产加速:如何使用结构化编译加速 C 项目构建?/src/mod.c: -------------------------------------------------------------------------------- 1 | int fib(int n) { 2 | if (n <= 1) 3 | return n; 4 | return fib(n - 1) + fib(n - 2); 5 | } 6 | -------------------------------------------------------------------------------- /25|可执行二进制文件里有什么?.md: -------------------------------------------------------------------------------- 1 | * ELF 编程 - 0x1: 2 | ```c 3 | #include 4 | #include 5 | 6 | void print_elf_type(uint16_t type_enum) { 7 | switch (type_enum) { 8 | case ET_REL: printf("A relocatable file."); break; 9 | case ET_DYN: printf("A shared object file."); break; 10 | case ET_NONE: printf("An unknown type."); break; 11 | case ET_EXEC: printf("An executable file."); break; 12 | case ET_CORE: printf("A core file."); break; 13 | } 14 | } 15 | 16 | int main (void) { 17 | Elf64_Ehdr elf_header; 18 | FILE* fp = fopen("./elf", "r"); 19 | fread(&elf_header, sizeof(Elf64_Ehdr), 1, fp); 20 | print_elf_type(elf_header.e_type); // "An executable file." 21 | fclose(fp); 22 | return 0; 23 | } 24 | ``` -------------------------------------------------------------------------------- /27 | 编译器在链接程序时发生了什么?.md: -------------------------------------------------------------------------------- 1 | * 静态链接的处理 - 0x1: 2 | ```c 3 | // main.c 4 | #define LEN 2 5 | extern int sharedArr[LEN]; 6 | extern int sum(int *arr, int n); 7 | int* array = sharedArr; 8 | int main(void) { 9 | int val = sum(array, LEN); 10 | return val; 11 | } 12 | ``` 13 | 14 | * 静态链接的处理 - 0x2: 15 | ```c 16 | // sum.c 17 | #define LEN 2 18 | int sharedArr[LEN] = { 1, 2 }; 19 | int sum(int *arr, int n) { 20 | int i, s = 0; 21 | for (i = 0; i < n; i++) { 22 | s += arr[i]; 23 | } 24 | return s; 25 | } 26 | ``` -------------------------------------------------------------------------------- /28|程序可以在运行时进行链接吗?.md: -------------------------------------------------------------------------------- 1 | * 运行时链接 - 0x1: 2 | ```c 3 | #include 4 | #include 5 | #include 6 | typedef double (*cos_t)(double); 7 | int main(void) { 8 | cos_t cosine; 9 | char *error; 10 | void* handle = dlopen("libm.so.6", RTLD_LAZY); 11 | if (!handle) { 12 | fprintf(stderr, "%s\n", dlerror()); 13 | exit(EXIT_FAILURE); 14 | } 15 | dlerror(); 16 | cosine = (cos_t) dlsym(handle, "cos"); 17 | error = dlerror(); 18 | if (error != NULL) { 19 | fprintf(stderr, "%s\n", error); 20 | exit(EXIT_FAILURE); 21 | } 22 | printf("%f\n", (*cosine)(2.0)); 23 | dlclose(handle); 24 | return 0; 25 | } 26 | ``` -------------------------------------------------------------------------------- /30|ABI 与 API 究竟有什么区别?.md: -------------------------------------------------------------------------------- 1 | * ABI - 不遵循 ABI 的程序能否运行? - 0x1: 2 | ```c 3 | // sub.c 4 | int sub(int x, int y) { 5 | return x - y; 6 | } 7 | ``` 8 | 9 | * ABI - 不遵循 ABI 的程序能否运行? - 0x2: 10 | ```asm 11 | # main.asm 12 | extern sub 13 | global _start 14 | section .text 15 | _start: 16 | and rsp, 0xfffffffffffffff0 17 | sub rsp, 1 18 | mov esi, 2 # the 1st param. 19 | mov edi, 1 # the 2nd param. 20 | call sub 21 | mov edi, eax 22 | mov eax, 60 23 | syscall 24 | ``` 25 | 26 | 27 | -------------------------------------------------------------------------------- /31|程序如何与操作系统交互?.md: -------------------------------------------------------------------------------- 1 | * 系统调用的基本实现 - 0x1: 2 | ```asm 3 | extern sub 4 | global _start 5 | section .text 6 | _start: 7 | and rsp,0xfffffffffffffff0 8 | sub rsp, 3 9 | mov esi, 2 10 | mov edi, 1 11 | call sub 12 | # use "int" to invoke a system call. 13 | mov ebx, eax 14 | mov eax, 1 15 | int 0x80 16 | ``` 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Jason Yu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # geektime-c 2 | The Repo holding all the code snippets related to the C course on Geektime. 3 | -------------------------------------------------------------------------------- /开篇词.md: -------------------------------------------------------------------------------- 1 | * 精确控制程序 - 0x1: 2 | ```c 3 | #include 4 | int main(void) { 5 | register int x = 1; 6 | int y = 2; 7 | printf("%d", x + y); 8 | return 0; 9 | } 10 | ``` 11 | 12 | * 精确控制程序 - 0x2: 13 | ```c 14 | #include 15 | int main(void) { 16 | int src = 1; 17 | int dst; 18 | asm ("mov %1, %0\n\t" 19 | "add $1, %0" 20 | : "=r" (dst) 21 | : "r" (src)); 22 | printf("%d\n", dst); 23 | } 24 | ``` 25 | -------------------------------------------------------------------------------- /课前热身.md: -------------------------------------------------------------------------------- 1 | * 指令集中的寄存器 - 0x1: 2 | ```c 3 | #include 4 | int main(void) { 5 | register long num asm("rax") = 0x100000000; 6 | asm("movl $0x1, %eax"); 7 | // asm("movw $0x1, %ax"); 8 | printf("%ld\n", num); 9 | return 0; 10 | } 11 | ``` 12 | --------------------------------------------------------------------------------