调试与测试
GDB、Valgrind、ASan、cmocka。
35 分钟
调试与测试
GDB 断点、Valgrind 内存检查与 cmocka 单元测试,是写出可靠 C 代码的三件套。对照 /roadmaps/c,本课覆盖常见工具链用法。
学习目标
- 用 GDB 设断点、单步、查看变量
- 了解 Valgrind 与 AddressSanitizer
- 编写 cmocka 风格的基本测试
- 建立「先失败用例再修复」的习惯
核心概念
GDB 调试
gcc -std=c11 -g -O0 -Wall app.c -o app
gdb ./app
(gdb) break main
(gdb) run
(gdb) next # 单步跳过函数
(gdb) step # 单步进入函数
(gdb) print x # 查看变量
(gdb) backtrace # 调用栈
(gdb) continue
示例程序与 ASan
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int sum_array(const int *arr, int n) {
int total = 0;
for (int i = 0; i < n; i++) {
total += arr[i];
}
return total;
}
/* 故意留 bug 供调试练习 */
char *broken_copy(const char *src) {
char *dst = malloc(strlen(src)); /* 少分配 1 字节 */
strcpy(dst, src);
return dst;
}
int main(void) {
int data[] = {1, 2, 3, 4, 5};
printf("sum=%d\n", sum_array(data, 5));
char *s = broken_copy("debug");
printf("copy=%s\n", s);
free(s);
return 0;
}
# AddressSanitizer 抓越界/泄漏
gcc -std=c11 -g -fsanitize=address app.c -o app_asan
./app_asan
cmocka 测试(概念)
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
static void test_sum(void **state) {
(void)state;
int arr[] = {1, 2, 3};
assert_int_equal(sum_array(arr, 3), 6);
}
int main(void) {
const struct CMUnitTest tests[] = {
cmocka_unit_test(test_sum),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}
类似 JUnit 的 assertEquals;C 项目常在 CI 中跑测试 + ASan 构建。
与 C++/Java 对照
| 工具 | C | C++ | Java |
|---|---|---|---|
| 调试器 | GDB / LLDB | 同左 | jdb / IDE |
| 内存检查 | Valgrind、ASan | 同左 | GC + 有限工具 |
| 单元测试 | cmocka、Unity | Google Test | JUnit |
| 覆盖率 | gcov、lcov | 同左 | JaCoCo |
Java 有 JVM 兜底部分错误;C 越界可能静默破坏内存,必须依赖工具与规范。