1. C语言学习路线与核心要点
作为一名从大学就开始接触C语言的程序员,我至今记得第一次用printf输出"Hello World"时的兴奋。C语言作为计算机世界的基石语言,其重要性不言而喻。不同于其他高级语言的"黑箱"特性,C语言能让我们真正理解计算机底层的工作原理。
学习C语言的核心路径可以分为四个阶段:基础语法、内存管理、算法实现和系统编程。每个阶段都需要扎实掌握关键概念,下面我将结合自己多年的实践经验,分享一套完整的C语言学习体系。
提示:初学者常犯的错误是过早接触复杂概念(如指针的高级用法),建议按照"变量→流程控制→函数→数组→指针→结构体→文件操作"的顺序循序渐进。
1.1 基础语法精要
C语言的基础语法是后续所有内容的基石。以下几个核心概念需要特别关注:
-
数据类型与运算符:理解整型、浮点型的存储方式,掌握sizeof运算符的实际用途。例如:
c复制printf("int size: %zu\n", sizeof(int)); // 观察不同平台下int的字节差异 -
流程控制结构:if-else、switch-case、for/while循环的嵌套使用。特别注意边界条件的处理:
c复制for(int i=0; i<=10; i++) { // 包含等于10的情况 // 循环体 } -
函数设计与调用:理解值传递和地址传递的区别,掌握递归函数的编写技巧:
c复制int factorial(int n) { return n <= 1 ? 1 : n * factorial(n-1); }
1.2 内存管理核心
C语言最强大的特性在于其对内存的直接操作能力,这也是最容易出错的部分:
-
指针的本质:指针就是内存地址,理解
int *p = &a中*和&的对称关系。通过这个简单的例子可以加深理解:c复制int a = 10; int *p = &a; printf("a=%d *p=%d\n", a, *p); // 输出相同的值 -
动态内存分配:malloc/free的正确使用模式,避免内存泄漏:
c复制int *arr = malloc(10 * sizeof(int)); if(arr == NULL) { // 错误处理 } // 使用内存 free(arr); arr = NULL; // 避免悬垂指针 -
数组与指针的关系:理解
arr[i]等价于*(arr+i)的实质,掌握指针算术运算的规则。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 常见问题与实战技巧
2.1 字符串处理要点
C语言的字符串以'\0'结尾的特性带来了许多需要注意的细节:
-
安全函数使用:优先选择
strncpy而非strcpy,避免缓冲区溢出:c复制char dest[10]; strncpy(dest, source, sizeof(dest)-1); dest[sizeof(dest)-1] = '\0'; // 确保终止符 -
常见字符串函数实现:自己实现strlen、strcat等函数是理解指针的好方法:
c复制size_t my_strlen(const char *s) { const char *p = s; while(*p) p++; return p - s; }
2.2 文件操作模式
文件操作是C语言实际应用的重要场景,需要注意不同模式的区别:
| 模式 | 描述 | 文件存在 | 文件不存在 |
|---|---|---|---|
| "r" | 只读 | 打开成功 | 打开失败 |
| "w" | 只写 | 清空内容 | 创建新文件 |
| "a" | 追加 | 保留内容 | 创建新文件 |
典型文件复制示例:
c复制FILE *src = fopen("source.txt", "rb");
FILE *dst = fopen("dest.txt", "wb");
if(!src || !dst) {
// 错误处理
}
char buffer[1024];
size_t bytes;
while((bytes = fread(buffer, 1, sizeof(buffer), src)) > 0) {
fwrite(buffer, 1, bytes, dst);
}
fclose(src);
fclose(dst);
3. 进阶主题与性能优化
3.1 数据结构实现
用C语言实现基础数据结构是提升编程能力的有效途径:
-
链表实现:注意头节点的处理和内存管理:
c复制typedef struct Node { int data; struct Node *next; } Node; void insert(Node **head, int data) { Node *new_node = malloc(sizeof(Node)); new_node->data = data; new_node->next = *head; *head = new_node; } -
二叉树遍历:递归和非递归实现的对比:
c复制void inorder(Node *root) { if(root) { inorder(root->left); printf("%d ", root->data); inorder(root->right); } }
3.2 性能优化技巧
-
循环优化:减少循环内部的计算量:
c复制// 不佳写法 for(int i=0; i<strlen(s); i++) {...} // 优化写法 int len = strlen(s); for(int i=0; i<len; i++) {...} -
内存对齐:结构体成员排列对性能的影响:
c复制struct Bad { char c; int i; char d; }; // 可能12字节 struct Good { int i; char c; char d; }; // 可能8字节
4. 开发环境与调试技巧
4.1 VS Code配置
现代开发环境中配置C语言环境的基本步骤:
- 安装C/C++扩展
- 配置tasks.json用于构建
- 配置launch.json用于调试
- 设置c_cpp_properties.json定义包含路径
示例tasks.json配置:
json复制{
"version": "2.0.0",
"tasks": [
{
"label": "build",
"type": "shell",
"command": "gcc",
"args": [
"-g",
"${file}",
"-o",
"${fileDirname}/${fileBasenameNoExtension}"
],
"group": {
"kind": "build",
"isDefault": true
}
}
]
}
4.2 GDB调试要点
掌握基本的GDB命令可以极大提高调试效率:
| 命令 | 功能 | 示例 |
|---|---|---|
| break | 设置断点 | break main.c:10 |
| run | 启动程序 | run |
| next | 单步执行 | next |
| 查看变量 | print x | |
| backtrace | 调用栈 | backtrace |
| watch | 监视点 | watch x |
典型调试会话:
code复制$ gcc -g program.c -o program
$ gdb ./program
(gdb) break main
(gdb) run
(gdb) next
(gdb) print x
(gdb) continue
5. 典型算法实现
5.1 排序算法
冒泡排序的标准实现及优化:
c复制void bubble_sort(int arr[], int n) {
for(int i=0; i<n-1; i++) {
int swapped = 0;
for(int j=0; j<n-i-1; j++) {
if(arr[j] > arr[j+1]) {
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
swapped = 1;
}
}
if(!swapped) break; // 提前终止
}
}
5.2 搜索算法
二分查找的实现要点:
c复制int binary_search(int arr[], int l, int r, int x) {
while(l <= r) {
int m = l + (r - l)/2; // 避免溢出
if(arr[m] == x) return m;
if(arr[m] < x) l = m + 1;
else r = m - 1;
}
return -1;
}
6. 工程实践建议
6.1 代码组织原则
-
头文件规范:使用头文件保护,避免重复包含:
c复制#ifndef MYHEADER_H #define MYHEADER_H // 声明内容 #endif -
模块化设计:合理划分.c和.h文件,保持高内聚低耦合。
6.2 Makefile编写
基础Makefile示例:
makefile复制CC = gcc
CFLAGS = -Wall -g
TARGET = program
SRCS = main.c utils.c
OBJS = $(SRCS:.c=.o)
all: $(TARGET)
$(TARGET): $(OBJS)
$(CC) $(CFLAGS) -o $@ $^
%.o: %.c
$(CC) $(CFLAGS) -c $<
clean:
rm -f $(OBJS) $(TARGET)
7. 跨平台开发注意事项
7.1 字节序问题
处理网络数据时的字节序转换:
c复制#include <arpa/inet.h>
uint32_t host_to_network(uint32_t hostlong) {
return htonl(hostlong);
}
uint32_t network_to_host(uint32_t netlong) {
return ntohl(netlong);
}
7.2 平台相关代码
使用条件编译处理平台差异:
c复制#ifdef _WIN32
// Windows特有代码
#include <windows.h>
#else
// Unix/Linux代码
#include <unistd.h>
#endif
8. 嵌入式C语言特性
8.1 寄存器操作
通过指针直接操作硬件寄存器:
c复制#define GPIO_BASE 0x40020000
typedef struct {
volatile uint32_t MODER;
volatile uint32_t OTYPER;
// 其他寄存器
} GPIO_TypeDef;
#define GPIOA ((GPIO_TypeDef *)GPIO_BASE)
void gpio_init() {
GPIOA->MODER |= 1 << (2*5); // 设置PA5为输出模式
}
8.2 位操作技巧
常用的位操作方法:
c复制#define BIT(n) (1 << (n))
// 设置位
reg |= BIT(3);
// 清除位
reg &= ~BIT(3);
// 切换位
reg ^= BIT(3);
// 检查位
if(reg & BIT(3)) {
// 位已设置
}
9. 安全编程实践
9.1 缓冲区安全
避免常见的缓冲区溢出问题:
c复制char buf[10];
// 不安全
// gets(buf);
// 安全
fgets(buf, sizeof(buf), stdin);
// 处理换行符
char *newline = strchr(buf, '\n');
if(newline) *newline = '\0';
9.2 整数溢出防护
检查整数运算的溢出情况:
c复制#include <limits.h>
int safe_add(int a, int b) {
if((b > 0 && a > INT_MAX - b) ||
(b < 0 && a < INT_MIN - b)) {
// 处理溢出
}
return a + b;
}
10. 现代C语言特性
10.1 C11标准特性
-
泛型选择:
c复制#define cbrt(X) _Generic((X), \ long double: cbrtl, \ default: cbrt, \ float: cbrtf \ )(X) -
匿名结构体/联合:
c复制struct person { char name[20]; union { int age; float height; }; };
10.2 静态分析工具
使用clang静态分析器检查代码:
bash复制$ clang --analyze program.c
11. 项目实战建议
11.1 小型项目选题
适合练习的C语言项目:
- 学生成绩管理系统
- 简单shell实现
- 文本编辑器基础功能
- 计算器程序
- 迷你数据库系统
11.2 代码质量保证
- 单元测试框架:使用Check等框架
- 代码格式化:clang-format统一风格
- 静态检查:cppcheck扫描潜在问题
- 版本控制:Git管理代码变更
12. 学习资源推荐
12.1 经典书籍
- 《C程序设计语言》(K&R)
- 《C Primer Plus》
- 《C陷阱与缺陷》
- 《C专家编程》
- 《深入理解C指针》
12.2 在线资源
- c语言中文网:基础教程全面
- GitHub上的开源项目:学习实际代码
- Stack Overflow:解决具体问题
- GeeksforGeeks:算法实现示例
- 中国大学MOOC:系统化课程
13. 常见面试问题
13.1 基础概念
- 指针和引用的区别
- static关键字的三种用法
- const的不同应用场景
- volatile的作用和使用场景
- 内存对齐的原理和影响
13.2 编程题
- 实现atoi函数
- 反转链表
- 检测循环链表
- 实现memcpy函数
- 查找字符串中最长不重复子串
14. 性能分析工具
14.1 gprof使用
基本性能分析步骤:
bash复制$ gcc -pg program.c -o program
$ ./program
$ gprof program gmon.out > analysis.txt
14.2 perf工具
Linux性能分析:
bash复制$ perf stat ./program # 基本统计
$ perf record ./program # 详细记录
$ perf report # 查看结果
15. 多线程编程
15.1 pthread基础
创建线程的基本模式:
c复制#include <pthread.h>
void *thread_func(void *arg) {
// 线程代码
return NULL;
}
int main() {
pthread_t tid;
pthread_create(&tid, NULL, thread_func, NULL);
pthread_join(tid, NULL);
return 0;
}
15.2 线程同步
互斥锁使用示例:
c复制pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void *thread_func(void *arg) {
pthread_mutex_lock(&mutex);
// 临界区代码
pthread_mutex_unlock(&mutex);
return NULL;
}
16. 网络编程基础
16.1 Socket编程
TCP服务器基本框架:
c复制int sock = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in addr = {
.sin_family = AF_INET,
.sin_port = htons(8080),
.sin_addr.s_addr = INADDR_ANY
};
bind(sock, (struct sockaddr*)&addr, sizeof(addr));
listen(sock, 5);
while(1) {
int client = accept(sock, NULL, NULL);
// 处理客户端连接
close(client);
}
16.2 常用网络函数
- inet_pton/inet_ntop:地址转换
- getaddrinfo:地址解析
- select/poll:I/O多路复用
- setsockopt:设置套接字选项
17. 与其它语言的交互
17.1 调用Shell命令
使用system函数执行命令:
c复制#include <stdlib.h>
int status = system("ls -l");
if(status == -1) {
// 错误处理
}
17.2 Python扩展
用C编写Python扩展模块:
c复制#include <Python.h>
static PyObject* hello(PyObject* self) {
return PyUnicode_FromString("Hello from C!");
}
static PyMethodDef methods[] = {
{"hello", (PyCFunction)hello, METH_NOARGS, NULL},
{NULL, NULL, 0, NULL}
};
static struct PyModuleDef module = {
PyModuleDef_HEAD_INIT,
"cext",
NULL,
-1,
methods
};
PyMODINIT_FUNC PyInit_cext(void) {
return PyModule_Create(&module);
}
18. 图形界面开发
18.1 GTK基础
简单GTK窗口示例:
c复制#include <gtk/gtk.h>
static void activate(GtkApplication *app, gpointer data) {
GtkWidget *window = gtk_application_window_new(app);
gtk_window_set_title(GTK_WINDOW(window), "Window");
gtk_window_set_default_size(GTK_WINDOW(window), 200, 200);
gtk_widget_show_all(window);
}
int main(int argc, char **argv) {
GtkApplication *app = gtk_application_new("org.example.app", G_APPLICATION_FLAGS_NONE);
g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
int status = g_application_run(G_APPLICATION(app), argc, argv);
g_object_unref(app);
return status;
}
18.2 事件处理
按钮点击事件示例:
c复制static void on_click(GtkWidget *widget, gpointer data) {
g_print("Button clicked\n");
}
GtkWidget *button = gtk_button_new_with_label("Click me");
g_signal_connect(button, "clicked", G_CALLBACK(on_click), NULL);
19. 代码优化进阶
19.1 内联汇编
使用asm关键字嵌入汇编:
c复制int add(int a, int b) {
asm volatile (
"add %0, %1, %2"
: "=r"(a)
: "r"(a), "r"(b)
);
return a;
}
19.2 编译器优化选项
GCC常用优化标志:
- -O1:基础优化
- -O2:推荐优化级别
- -O3:激进优化
- -Os:优化代码大小
- -Ofast:不考虑标准符合性
20. 调试复杂问题
20.1 内存错误调试
使用Valgrind检测内存问题:
bash复制$ valgrind --leak-check=full ./program
20.2 核心转储分析
分析核心转储文件:
bash复制$ gdb program core
(gdb) backtrace
(gdb) print variable
21. 嵌入式开发特殊考虑
21.1 中断处理
基本中断服务例程:
c复制void __attribute__((interrupt)) ISR(void) {
// 中断处理代码
}
21.2 低功耗编程
进入低功耗模式:
c复制#define WFI() __asm volatile ("wfi")
void enter_low_power(void) {
// 配置低功耗模式
WFI();
}
22. 现代开发实践
22.1 持续集成
简单的CI脚本示例:
bash复制#!/bin/bash
set -e
# 构建
gcc -Wall -Werror -g program.c -o program
# 测试
./test_program.sh
# 静态分析
cppcheck --enable=all program.c
22.2 代码审查要点
C语言代码审查检查清单:
- 指针使用是否安全
- 所有错误路径是否处理
- 是否存在潜在的整数溢出
- 资源是否确保释放
- 关键操作是否有日志记录
23. 数学计算实现
23.1 浮点运算
精确浮点比较方法:
c复制#include <math.h>
int float_equal(double a, double b) {
return fabs(a - b) < 1e-9;
}
23.2 随机数生成
使用rand的正确方式:
c复制#include <stdlib.h>
#include <time.h>
srand(time(NULL)); // 初始化种子
int r = rand() % 100; // 0-99随机数
24. 日期时间处理
24.1 时间获取
获取当前时间的标准方法:
c复制#include <time.h>
time_t now = time(NULL);
struct tm *tm = localtime(&now);
printf("%04d-%02d-%02d\n",
tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday);
24.2 时间计算
计算时间差:
c复制struct timespec start, end;
clock_gettime(CLOCK_MONOTONIC, &start);
// 执行操作
clock_gettime(CLOCK_MONOTONIC, &end);
double elapsed = (end.tv_sec - start.tv_sec) +
(end.tv_nsec - start.tv_nsec) / 1e9;
25. 实用代码片段
25.1 宏技巧
调试用宏定义:
c复制#define DEBUG 1
#if DEBUG
#define LOG(fmt, ...) printf("[%s:%d] " fmt, __FILE__, __LINE__, ##__VA_ARGS__)
#else
#define LOG(fmt, ...)
#endif
25.2 位运算技巧
常用位操作:
c复制// 判断奇偶
#define IS_ODD(n) ((n) & 1)
// 交换两数
#define SWAP(a, b) do { (a) ^= (b); (b) ^= (a); (a) ^= (b); } while(0)
// 取最小值
#define MIN(a, b) ((a) < (b) ? (a) : (b))
26. 跨语言调用
26.1 调用C++代码
使用extern "C"兼容C调用:
cpp复制// cpp_code.cpp
extern "C" {
int add(int a, int b) {
return a + b;
}
}
26.2 从Java调用
使用JNI接口:
c复制#include <jni.h>
JNIEXPORT jstring JNICALL
Java_com_example_HelloJNI_sayHello(JNIEnv *env, jobject obj) {
return (*env)->NewStringUTF(env, "Hello from JNI!");
}
27. 嵌入式Linux开发
27.1 设备驱动基础
字符设备驱动框架:
c复制#include <linux/module.h>
#include <linux/fs.h>
static int device_open(struct inode *inode, struct file *file) {
printk(KERN_INFO "Device opened\n");
return 0;
}
static struct file_operations fops = {
.open = device_open,
};
static int __init mydriver_init(void) {
register_chrdev(0, "mydriver", &fops);
return 0;
}
module_init(mydriver_init);
27.2 内核模块编译
基本Makefile:
makefile复制obj-m := mydriver.o
KDIR := /lib/modules/$(shell uname -r)/build
all:
make -C $(KDIR) M=$(PWD) modules
clean:
make -C $(KDIR) M=$(PWD) clean
28. 安全编码实践
28.1 防御性编程
输入验证示例:
c复制int safe_divide(int a, int b, int *result) {
if(b == 0) return -1;
if((a == INT_MIN) && (b == -1)) return -1;
*result = a / b;
return 0;
}
28.2 敏感数据处理
安全内存清零:
c复制#include <string.h>
void secure_clear(void *s, size_t n) {
volatile unsigned char *p = s;
while(n--) *p++ = 0;
}
29. 性能敏感代码
29.1 循环展开
手动循环展开示例:
c复制// 常规循环
for(int i=0; i<100; i++) {
process(i);
}
// 展开4次
for(int i=0; i<100; i+=4) {
process(i);
process(i+1);
process(i+2);
process(i+3);
}
29.2 数据局部性
优化数据访问模式:
c复制// 不佳:列优先访问
for(int j=0; j<cols; j++) {
for(int i=0; i<rows; i++) {
matrix[i][j] = 0;
}
}
// 优化:行优先访问
for(int i=0; i<rows; i++) {
for(int j=0; j<cols; j++) {
matrix[i][j] = 0;
}
}
30. 代码可移植性
30.1 固定宽度整数
使用stdint.h确保类型一致性:
c复制#include <stdint.h>
int32_t signed32; // 保证32位有符号整数
uint64_t unsigned64; // 保证64位无符号整数
30.2 字节序检测
运行时检测系统字节序:
c复制int is_little_endian() {
uint16_t x = 0x0001;
return *(uint8_t*)&x == 0x01;
}
31. 信号处理
31.1 基本信号捕获
处理Ctrl+C中断:
c复制#include <signal.h>
#include <stdio.h>
volatile sig_atomic_t flag = 0;
void handler(int sig) {
flag = 1;
}
int main() {
signal(SIGINT, handler);
while(!flag) {
// 主循环
}
printf("Received SIGINT\n");
return 0;
}
31.2 信号安全函数
信号处理函数中只能调用异步信号安全函数,如:
- write
- _exit
- signal
- 部分字符串函数
32. 进程管理
32.1 创建子进程
fork基本用法:
c复制#include <unistd.h>
#include <sys/wait.h>
pid_t pid = fork();
if(pid == 0) {
// 子进程
_exit(0);
} else if(pid > 0) {
// 父进程
wait(NULL);
} else {
// 错误
}
32.2 进程间通信
管道使用示例:
c复制int fd[2];
pipe(fd);
if(fork() == 0) {
close(fd[0]); // 关闭读端
write(fd[1], "hello", 6);
close(fd[1]);
} else {
close(fd[1]); // 关闭写端
char buf[6];
read(fd[0], buf, sizeof(buf));
close(fd[0]);
}
33. 系统编程接口
33.1 文件描述符操作
复制文件描述符:
c复制int new_fd = dup(old_fd); // 复制
int new_fd2 = dup2(old_fd, desired_fd); // 指定新fd
33.2 文件状态获取
使用stat获取文件信息:
c复制#include <sys/stat.h>
struct stat st;
if(stat("file.txt", &st) == 0) {
printf("Size: %ld\n", st.st_size);
printf("Mode: %o\n", st.st_mode);
}
34. 动态链接库
34.1 创建共享库
编译共享库:
bash复制$ gcc -shared -fPIC -o libmylib.so mylib.c
34.2 动态加载
运行时加载库:
c复制#include <dlfcn.h>
void *handle = dlopen("libmylib.so", RTLD_LAZY);
if(handle) {
void (*func)() = dlsym(handle, "my_function");
if(func) func();
dlclose(handle);
}
35. 异常处理模式
35.1 setjmp/longjmp
非局部跳转示例:
c复制#include <setjmp.h>
jmp_buf env;
void func() {
printf("Before jump\n");
longjmp(env, 1);
printf("After jump\n"); // 不会执行
}
int main() {
if(setjmp(env) == 0) {
func();
} else {
printf("Jumped back\n");
}
return 0;
}
35.2 错误处理策略
统一的错误处理模式:
c复制typedef enum {
ERR_NONE,
ERR_INVALID_INPUT,
ERR_MEMORY,
ERR_IO
} ErrorCode;
ErrorCode do_something(int param) {
if(param < 0) return ERR_INVALID_INPUT;
// 其他操作
return ERR_NONE;
}
36. 预处理技巧
36.1 条件编译
平台相关代码处理:
c复制#if defined(_WIN32)
// Windows特有代码
#elif defined(__linux__)
// Linux特有代码
#else
#error "Unsupported platform"
#endif
36.2 X宏技术
避免重复代码:
c复制#define COLORS \
X(RED, "red") \
X(GREEN, "green") \
X(BLUE, "blue")
enum Color {
#define X(name, str) name,
COLORS
#undef X
};
const char *color_to_string(enum Color c) {
switch(c) {
#define X(name, str) case name: return str;
COLORS
#undef X
}
return "unknown";
}
37. 代码生成技术
37.1 模板代码生成
使用脚本生成重复代码:
bash复制#!/bin/bash
for i in {1..10}; do
echo "int func$i(void) { return $i; }"
done > generated.c
37.2 元编程技巧
使用宏生成函数:
c复制#define DECLARE_FUNC(n) \
int func##n(void) { return n; }
DECLARE_FUNC(1)
DECLARE_FUNC(2)
DECLARE_FUNC(3)
38. 嵌入式数据库
38.1 SQLite集成
基本SQLite操作:
c复制#include <sqlite3.h>
sqlite3 *db;
sqlite3_open("test.db", &db);
char *err;
sqlite3_exec(db, "CREATE TABLE test(id INT, name TEXT)", NULL, NULL, &err);
sqlite3_stmt *stmt;
sqlite3_prepare_v2(db, "INSERT INTO test VALUES(?, ?)", -1, &stmt, NULL);
sqlite3_bind_int(stmt, 1, 1);
sqlite3_bind_text(stmt, 2, "Alice", -1, SQLITE_STATIC);
sqlite3_step(stmt);
sqlite3_finalize(stmt);
sqlite3_close(db);
38.2 性能优化
SQLite事务处理:
c复制sqlite3_exec(db, "BEGIN TRANSACTION", NULL, NULL, NULL);
// 批量插入操作
sqlite3_exec(db, "COMMIT", NULL, NULL, NULL);
39. 测试驱动开发
39.1 单元测试框架
使用Unity测试框架:
c复制#include "unity.h"
void setUp(void) {
// 初始化代码
}
void tearDown(void) {
// 清理代码
}
void test_addition(void) {
TEST_ASSERT_EQUAL(5, add(2, 3));
}
int main(void) {
UNITY_BEGIN();
RUN_TEST(test_addition);
return UNITY_END();
}
39.2 测试覆盖率
生成覆盖率报告:
bash复制$ gcc -fprofile-arcs -ftest-coverage program.c -o program
$ ./program
$ gcov program.c
40. 代码重构技巧
40.1 函数拆分
长函数重构示例:
c复制// 重构前
void process_data(Data *data) {
// 50行复杂逻辑
}
// 重构后
void validate_input(Data *data) {
// 验证逻辑
}
void transform_data(Data *data) {
// 转换逻辑
}
void save_result(Data *data) {
// 保存逻辑
}
void process_data(Data *data) {
validate_input(data);
transform_data(data);
save_result(data);
}
40.2 消除重复
提取公共代码:
c复制// 重复代码
void func1() {
setup();
// 特有逻辑
cleanup();
}
void func2() {
setup();
// 特有逻辑
cleanup();
}
// 重构后
void with_setup(void (*func)()) {
setup();
func();
cleanup();
}
void func1_logic() {
// 特有逻辑
}
void func2_logic() {
// 特有逻辑
}
void func1() { with_setup(func1_logic); }
void func2() { with_setup(func2_logic); }
41. 并发模式
41.1 生产者消费者
使用条件变量实现:
c复制pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
Queue queue;
void *producer(void *arg) {
while(1) {
Item item = produce_item();
pthread_mutex_lock(&mutex);
enqueue(&queue, item);
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
}
}
void *consumer(void *arg) {
while(1) {
pthread_mutex_lock(&mutex);
while(is_empty(&queue)) {
pthread_cond_wait(&cond, &mutex);
}
Item item = dequeue(&queue);
pthread_mutex_unlock(&mutex);
consume_item(item);
}
}
41.2 读写锁模式
读写锁应用:
c复制pthread_rwlock_t lock = PTHREAD_RWLOCK_INITIALIZER;
void reader() {
pthread_rwlock_rdlock(&lock);
// 读取数据
pthread_rwlock_unlock(&lock);
}
void writer() {
pthread_rwlock_wrlock(&lock);
// 修改数据
pthread_rwlock_unlock(&lock);
}
42. 内存池实现
42.1 固定大小内存池
基础实现:
c复制typedef struct {
void *free_list;
size_t block_size;
} MemoryPool;
void pool_init(MemoryPool *pool, size_t block_size) {
pool->block_size = block_size;
pool->free_list = NULL;
}
void *pool_alloc(MemoryPool *pool) {
if(pool->free_list) {
void *block = pool->free_list;
pool->free_list
