1. C语言常见陷阱与避坑指南
作为一门诞生于1972年的经典编程语言,C语言至今仍是系统编程、嵌入式开发等领域的基石。但正是由于其接近硬件的特性,新手在学习和使用过程中常常会遇到各种"坑"。这些陷阱轻则导致程序崩溃,重则引发内存泄漏等严重问题。本文将结合我十余年的C语言开发经验,系统梳理那些教科书上不会告诉你,但实际开发中必然会遇到的典型问题。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 指针与内存管理陷阱
2.1 野指针问题
野指针是指向无效内存地址的指针,通常由以下情况导致:
- 指针未初始化
- 指针指向的内存已被释放
- 指针越界访问
c复制int *p; // 未初始化
*p = 10; // 危险操作!
char *str = malloc(10);
free(str);
str[0] = 'a'; // 使用已释放内存
重要提示:养成初始化指针为NULL的习惯,使用前检查指针有效性
2.2 内存泄漏检测
内存泄漏是C程序中最常见的问题之一。以下是一个典型场景:
c复制void process_data() {
char *buffer = malloc(1024);
// 处理数据...
// 忘记free(buffer)
}
检测工具推荐:
- Valgrind(Linux平台)
- Dr. Memory(Windows平台)
- AddressSanitizer(GCC/Clang内置)
3. 数组与字符串陷阱
3.1 数组越界访问
C语言不检查数组边界,这可能导致严重的安全漏洞:
c复制int arr[5] = {0};
arr[5] = 10; // 越界写入
防御性编程建议:
- 明确数组大小并使用宏定义
- 在访问前检查索引有效性
- 考虑使用安全函数(如snprintf替代sprintf)
3.2 字符串处理陷阱
字符串相关的常见错误包括:
- 忘记预留NULL终止符空间
- 使用不安全的字符串函数
- 缓冲区溢出
c复制char src[10] = "hello";
char dest[5];
strcpy(dest, src); // 缓冲区溢出
安全替代方案:
- strncpy代替strcpy
- snprintf代替sprintf
- 使用strlcpy(如果平台支持)
4. 预处理与宏定义陷阱
4.1 宏定义中的副作用
宏是简单的文本替换,可能导致意外行为:
c复制#define SQUARE(x) x * x
int a = 5;
int b = SQUARE(a + 1); // 展开为 a + 1 * a + 1 = 11
正确写法:
c复制#define SQUARE(x) ((x) * (x))
4.2 条件编译陷阱
c复制#if DEBUG == 1
// 调试代码
#else
// 生产代码
#endif
常见错误:
- 忘记定义DEBUG宏
- 条件判断逻辑错误
- 嵌套条件编译导致代码难以维护
5. 结构体与字节对齐问题
5.1 结构体大小计算
由于内存对齐,结构体大小可能大于成员大小之和:
c复制struct example {
char a; // 1字节
int b; // 4字节(可能需要4字节对齐)
short c; // 2字节
}; // 总大小可能是12字节而非7字节
解决方法:
- 使用#pragma pack指定对齐方式
- 合理安排成员顺序减少填充
5.2 结构体赋值陷阱
直接比较或复制结构体可能导致问题:
c复制struct point p1 = {1, 2};
struct point p2 = {1, 2};
if (p1 == p2) { ... } // 错误!不能直接比较结构体
正确做法:
- 逐个比较成员
- 使用memcmp(需确保无填充字节)
- 实现专门的比较函数
6. 函数与参数传递陷阱
6.1 值传递与指针传递混淆
c复制void modify(int x) { x = 10; }
void real_modify(int *x) { *x = 10; }
int main() {
int a = 5;
modify(a); // a仍然是5
real_modify(&a); // a变为10
}
6.2 可变参数函数风险
c复制#include <stdarg.h>
int sum(int count, ...) {
va_list args;
va_start(args, count);
int total = 0;
for (int i = 0; i < count; i++) {
total += va_arg(args, int);
}
va_end(args);
return total;
}
潜在问题:
- 参数类型不匹配
- 参数数量错误
- 平台依赖性
7. 多文件编程陷阱
7.1 头文件重复包含
典型解决方案:
c复制#ifndef MY_HEADER_H
#define MY_HEADER_H
// 头文件内容
#endif
7.2 外部链接问题
c复制// file1.c
int global_var; // 外部链接
// file2.c
extern int global_var; // 正确声明
常见错误:
- 忘记extern声明
- 多个定义冲突
- static使用不当
8. 标准库使用陷阱
8.1 文件操作常见错误
c复制FILE *fp = fopen("file.txt", "r");
if (fp == NULL) {
perror("打开文件失败");
return;
}
char buffer[100];
while (fgets(buffer, sizeof(buffer), fp) != NULL) {
// 处理每行
}
fclose(fp); // 经常被忘记!
8.2 时间函数陷阱
c复制time_t now = time(NULL);
struct tm *local = localtime(&now); // 返回静态缓冲区指针
char time_str[100];
strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", local);
注意:
- localtime返回指针指向静态存储区
- 多线程环境下应使用localtime_r
- 时区处理需谨慎
9. 优化与性能陷阱
9.1 过度优化问题
c复制// 原始代码
for (int i = 0; i < n; i++) {
array[i] = i * i;
}
// "优化"后(可能适得其反)
register int i;
int *ptr = array;
for (i = 0; i < n; i++) {
*ptr++ = i * i;
}
优化建议:
- 优先保证代码可读性
- 使用profiler定位真正瓶颈
- 了解编译器优化能力
9.2 volatile关键字误用
c复制volatile int flag = 0;
// 线程1
void set_flag() { flag = 1; }
// 线程2
while (flag == 0) {
// 等待
}
适用场景:
- 硬件寄存器访问
- 多线程共享变量
- 信号处理程序中的变量
10. 调试与错误处理技巧
10.1 断言使用
c复制#include <assert.h>
void process(int *ptr) {
assert(ptr != NULL);
// 处理逻辑
}
注意事项:
- 仅用于调试版本
- 不要用于检查用户输入
- 断言失败会终止程序
10.2 errno使用模式
c复制#include <errno.h>
#include <string.h>
FILE *fp = fopen("nonexistent.txt", "r");
if (fp == NULL) {
fprintf(stderr, "错误: %s\n", strerror(errno));
}
最佳实践:
- 在调用可能失败的函数后立即检查errno
- 某些函数调用前需要先清除errno
- 注意线程安全性
11. 现代C语言实践
11.1 C11新特性应用
c复制// 类型泛型宏
#define cbrt(X) _Generic((X), \
long double: cbrtl, \
default: cbrt, \
float: cbrtf \
)(X)
// 匿名结构体/联合
struct person {
char name[50];
union {
int age;
float height;
};
};
11.2 静态分析工具
推荐工具:
- Clang Static Analyzer
- Cppcheck
- Coverity
集成方法:
- 在CI/CD流程中加入静态检查
- 开发时使用编辑器插件
- 定期运行完整分析
12. 跨平台开发注意事项
12.1 数据类型大小差异
c复制#include <stdint.h>
// 可移植类型定义
int32_t fixed_size_int;
uint64_t fixed_size_unsigned;
12.2 字节序问题
c复制uint32_t value = 0x12345678;
uint8_t *p = (uint8_t *)&value;
if (p[0] == 0x12) {
// 大端序
} else {
// 小端序
}
处理建议:
- 使用htonl/ntohl等函数
- 定义明确的网络协议
- 考虑使用文本协议(如JSON)
13. 嵌入式开发特殊考量
13.1 寄存器操作模式
c复制#define PORT_A (*(volatile uint32_t *)0x40000000)
void init_port() {
PORT_A = 0x55; // 直接操作硬件寄存器
}
注意事项:
- 确保地址正确
- 使用volatile防止优化
- 考虑位域操作
13.2 中断处理要点
c复制void __attribute__((interrupt)) timer_isr() {
// 中断处理逻辑
// 保持简短
// 避免阻塞操作
}
最佳实践:
- 禁用中断中的关键操作
- 注意寄存器保存
- 避免调用不可重入函数
14. 性能敏感代码优化
14.1 缓存友好编程
c复制// 不好的访问模式
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
array[j][i] = 0; // 按列访问
}
}
// 好的访问模式
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
array[i][j] = 0; // 按行访问
}
}
14.2 内联函数应用
c复制static inline int max(int a, int b) {
return a > b ? a : b;
}
适用场景:
- 小型频繁调用的函数
- 性能关键路径
- 替代部分宏函数
15. 安全编程实践
15.1 防止缓冲区溢出
c复制char buf[100];
fgets(buf, sizeof(buf), stdin); // 安全输入
// 替代不安全的gets
// 替代不安全的scanf("%s", buf)
15.2 敏感数据处理
c复制void process_password(char *pwd) {
// 使用后立即清除
memset(pwd, 0, strlen(pwd));
free(pwd);
}
安全建议:
- 最小化敏感数据存活时间
- 避免将密码等写入日志
- 使用安全的内存清除函数
16. 构建系统与工具链
16.1 Makefile常见错误
makefile复制# 错误示例:缺少依赖关系
program: file1.o file2.o
gcc -o $@ $^
# 正确示例
program: file1.o file2.o
gcc -o $@ $^
file1.o: file1.c header.h
gcc -c $<
file2.o: file2.c header.h
gcc -c $<
16.2 编译器警告选项
推荐编译选项:
bash复制gcc -Wall -Wextra -Werror -pedantic -std=c11
警告处理原则:
- 将警告视为错误
- 定期检查新警告
- 了解每个警告的含义
17. 代码风格与可维护性
17.1 命名约定
c复制// 不好的命名
int a;
void fn();
// 好的命名
int connection_count;
void calculate_average();
17.2 注释规范
c复制/*
* 计算两个点的欧式距离
* @param x1 第一个点的x坐标
* @param y1 第一个点的y坐标
* @param x2 第二个点的x坐标
* @param y2 第二个点的y坐标
* @return 两点之间的距离
*/
double distance(double x1, double y1, double x2, double y2);
18. 测试与验证策略
18.1 单元测试框架
c复制// 使用Check框架示例
START_TEST(test_addition) {
ck_assert_int_eq(add(2, 3), 5);
}
END_TEST
18.2 模糊测试应用
c复制// 使用libFuzzer示例
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
if (size < 10) return 0;
process_input((char *)data);
return 0;
}
19. 并发编程挑战
19.1 线程安全实现
c复制#include <pthread.h>
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
int shared_counter = 0;
void *thread_func(void *arg) {
pthread_mutex_lock(&lock);
shared_counter++;
pthread_mutex_unlock(&lock);
return NULL;
}
19.2 原子操作使用
c复制#include <stdatomic.h>
atomic_int counter = ATOMIC_VAR_INIT(0);
void increment() {
atomic_fetch_add(&counter, 1);
}
20. 代码重构技巧
20.1 函数拆分原则
c复制// 重构前
void process_data() {
// 读取数据
// 解析数据
// 验证数据
// 处理数据
// 输出结果
}
// 重构后
void process_data() {
Data *data = read_data();
parse_data(data);
validate_data(data);
calculate_results(data);
output_results(data);
}
20.2 消除重复代码
c复制// 重复代码
void print_user_info(User *u) {
printf("Name: %s\n", u->name);
printf("Age: %d\n", u->age);
}
void log_user_info(User *u) {
fprintf(logfile, "Name: %s\n", u->name);
fprintf(logfile, "Age: %d\n", u->age);
}
// 重构后
void output_user_info(User *u, FILE *out) {
fprintf(out, "Name: %s\n", u->name);
fprintf(out, "Age: %d\n", u->age);
}
21. 第三方库集成
21.1 库版本管理
c复制// 使用pkg-config示例
// 编译命令:gcc -o program program.c `pkg-config --cflags --libs openssl`
21.2 API封装策略
c复制// 原始调用
void db_connect_raw() {
mysql_init();
mysql_real_connect();
// ...
}
// 封装后
typedef struct {
// 连接参数
} DBConnection;
DBConnection *db_connect();
void db_disconnect(DBConnection *conn);
22. 性能分析技术
22.1 Profiler使用
bash复制# 使用gprof示例
gcc -pg program.c -o program
./program
gprof program gmon.out > analysis.txt
22.2 基准测试方法
c复制#include <time.h>
void benchmark() {
clock_t start = clock();
// 测试代码
clock_t end = clock();
double elapsed = (double)(end - start) / CLOCKS_PER_SEC;
printf("耗时: %f秒\n", elapsed);
}
23. 异常处理模式
23.1 错误码返回
c复制typedef enum {
SUCCESS,
INVALID_INPUT,
MEMORY_ERROR,
IO_ERROR
} ErrorCode;
ErrorCode process_file(const char *filename) {
if (filename == NULL) return INVALID_INPUT;
// ...
return SUCCESS;
}
23.2 长跳转应用
c复制#include <setjmp.h>
jmp_buf env;
void process() {
if (error_occurred) {
longjmp(env, 1);
}
}
int main() {
if (setjmp(env) == 0) {
process();
} else {
// 错误处理
}
}
24. 编译器特性利用
24.1 属性语法应用
c复制// 函数不返回
void fatal_error() __attribute__((noreturn));
// 强制内联
__attribute__((always_inline)) void critical_function();
24.2 内置函数使用
c复制// GCC内置示例
int count = __builtin_popcount(0x0F); // 计算1的位数
void *ptr = __builtin_alloca(100); // 栈上分配
25. 低级编程技巧
25.1 位操作优化
c复制// 判断是否为2的幂
int is_power_of_two(uint32_t x) {
return x && !(x & (x - 1));
}
// 交换两个变量
void swap(int *a, int *b) {
*a ^= *b;
*b ^= *a;
*a ^= *b;
}
25.2 内联汇编应用
c复制// GCC内联汇编示例
uint32_t read_tsc() {
uint32_t low, high;
asm volatile("rdtsc" : "=a"(low), "=d"(high));
return low;
}
26. 代码生成技术
26.1 宏元编程
c复制#define DECLARE_VECTOR(type) \
typedef struct { \
type *data; \
size_t size; \
} vector_##type; \
void vector_##type##_init(vector_##type *v); \
void vector_##type##_push(vector_##type *v, type value);
// 实例化
DECLARE_VECTOR(int)
DECLARE_VECTOR(double)
26.2 动态代码生成
c复制#include <sys/mman.h>
void generate_code(uint8_t *buffer) {
// x86的mov eax, 42; ret
buffer[0] = 0xB8;
*(int *)(buffer + 1) = 42;
buffer[5] = 0xC3;
}
int main() {
uint8_t *mem = mmap(NULL, 4096, PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
generate_code(mem);
int (*func)() = (int (*)())mem;
printf("%d\n", func());
munmap(mem, 4096);
}
27. 调试高级技巧
27.1 核心转储分析
bash复制# 生成核心转储
ulimit -c unlimited
./program
# 分析
gdb program core
27.2 条件断点设置
bash复制(gdb) break file.c:123 if count > 100
(gdb) watch variable if condition
28. 跨语言交互
28.1 C与Python交互
c复制// 使用Python C API示例
#include <Python.h>
static PyObject* hello(PyObject* self) {
return PyUnicode_FromString("Hello from C!");
}
static PyMethodDef methods[] = {
{"hello", (PyCFunction)hello, METH_NOARGS, "Say hello"},
{NULL, NULL, 0, NULL}
};
static struct PyModuleDef module = {
PyModuleDef_HEAD_INIT,
"cext",
NULL,
-1,
methods
};
PyMODINIT_FUNC PyInit_cext(void) {
return PyModule_Create(&module);
}
28.2 C与Rust交互
rust复制// Rust侧
#[no_mangle]
pub extern "C" fn rust_add(a: i32, b: i32) -> i32 {
a + b
}
c复制// C侧
extern int32_t rust_add(int32_t a, int32_t b);
int main() {
printf("%d\n", rust_add(2, 3));
}
29. 代码静态分析
29.1 Clang静态分析器
bash复制scan-build make
29.2 自定义检查规则
python复制# 使用Clang Python绑定示例
import clang.cindex
def check_function_length(node):
if node.kind == clang.cindex.CursorKind.FUNCTION_DECL:
# 计算函数体行数
pass
30. 持续集成实践
30.1 自动化测试集成
yaml复制# .travis.yml示例
language: c
compiler:
- gcc
- clang
script:
- make test
30.2 静态分析集成
yaml复制# GitHub Actions示例
jobs:
analyze:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: sudo apt-get install cppcheck
- run: cppcheck --enable=all --error-exitcode=1 src/
31. 代码文档生成
31.1 Doxygen应用
c复制/**
* @brief 计算两个数的和
* @param a 第一个加数
* @param b 第二个加数
* @return 两数之和
*/
int add(int a, int b);
31.2 文档生成流程
bash复制doxygen Doxyfile
32. 内存调试技巧
32.1 Electric Fence使用
bash复制LD_PRELOAD=libefence.so ./program
32.2 自定义内存分配器
c复制typedef struct {
size_t allocations;
size_t deallocations;
} AllocStats;
void *tracking_malloc(size_t size) {
static AllocStats stats = {0};
stats.allocations++;
return malloc(size);
}
33. 信号处理注意事项
33.1 异步信号安全
c复制void handler(int sig) {
// 只能调用异步信号安全函数
char msg[] = "Signal received\n";
write(STDERR_FILENO, msg, sizeof(msg));
_exit(1);
}
33.2 信号竞争条件
c复制volatile sig_atomic_t flag = 0;
void handler(int sig) {
flag = 1;
}
int main() {
signal(SIGINT, handler);
while (!flag) {
// 主循环
}
}
34. 浮点数处理陷阱
34.1 精度问题
c复制float a = 0.1;
float b = 0.2;
float c = a + b;
if (c == 0.3) { // 可能不成立
printf("相等\n");
}
解决方案:
- 使用误差范围比较
- 考虑使用定点数
- 必要时使用更高精度类型
34.2 NaN和无穷大检查
c复制#include <math.h>
double result = some_calculation();
if (isnan(result)) {
// 处理NaN情况
}
if (isinf(result)) {
// 处理无穷大情况
}
35. 预处理技巧
35.1 X宏应用
c复制#define COLORS \
X(RED) \
X(GREEN) \
X(BLUE)
enum Color {
#define X(c) c,
COLORS
#undef X
};
const char *color_names[] = {
#define X(c) #c,
COLORS
#undef X
};
35.2 编译时断言
c复制#define STATIC_ASSERT(cond) typedef char static_assert[(cond)?1:-1]
STATIC_ASSERT(sizeof(int) == 4);
36. 多线程同步模式
36.1 读写锁应用
c复制#include <pthread.h>
pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
// 读线程
pthread_rwlock_rdlock(&rwlock);
// 读操作
pthread_rwlock_unlock(&rwlock);
// 写线程
pthread_rwlock_wrlock(&rwlock);
// 写操作
pthread_rwlock_unlock(&rwlock);
36.2 条件变量使用
c复制pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int ready = 0;
// 等待线程
pthread_mutex_lock(&mutex);
while (!ready) {
pthread_cond_wait(&cond, &mutex);
}
pthread_mutex_unlock(&mutex);
// 通知线程
pthread_mutex_lock(&mutex);
ready = 1;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
37. 网络编程陷阱
37.1 字节序转换
c复制#include <arpa/inet.h>
uint32_t net_long = htonl(host_long); // 主机到网络
uint32_t host_long = ntohl(net_long); // 网络到主机
37.2 非阻塞IO处理
c复制int flags = fcntl(sockfd, F_GETFL, 0);
fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
// 检查EAGAIN/EWOULDBLOCK
ssize_t n = recv(sockfd, buf, len, 0);
if (n == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
// 稍后重试
}
38. 动态加载技巧
38.1 dlopen使用模式
c复制#include <dlfcn.h>
void *handle = dlopen("libmylib.so", RTLD_LAZY);
if (!handle) {
fprintf(stderr, "%s\n", dlerror());
exit(1);
}
typedef int (*func_t)(int);
func_t myfunc = (func_t)dlsym(handle, "my_function");
if (!myfunc) {
fprintf(stderr, "%s\n", dlerror());
dlclose(handle);
exit(1);
}
int result = myfunc(42);
dlclose(handle);
38.2 插件架构实现
c复制// 插件接口定义
typedef struct {
const char *name;
void (*init)();
void (*process)(void *data);
void (*cleanup)();
} Plugin;
// 主程序加载插件
void load_plugin(const char *path) {
// 使用dlopen加载
// 查找并调用插件函数
}
39. 性能优化模式
39.1 循环展开
c复制// 展开前
for (int i = 0; i < 100; i++) {
process(i);
}
// 展开后
for (int i = 0; i < 100; i += 4) {
process(i);
process(i + 1);
process(i + 2);
process(i + 3);
}
39.2 数据预取
c复制#include <xmmintrin.h>
for (int i = 0; i < size; i++) {
_mm_prefetch(&data[i + 16], _MM_HINT_T0);
process(data[i]);
}
40. 嵌入式特定优化
40.1 寄存器变量使用
c复制register int counter asm("r12");
40.2 位带操作
c复制#define BITBAND(addr, bit) ((volatile uint32_t*)(0x42000000 + ((uint32_t)(addr) - 0x40000000)*32 + (bit)*4))
volatile uint32_t *led = BITBAND(&GPIOA->ODR, 5);
*led = 1; // 原子操作单个位
41. 安全编码实践
41.1 防御性编程
c复制void process_buffer(char *buf, size_t len) {
if (buf == NULL || len == 0 || len > MAX_LEN) {
return;
}
// 安全处理
}
41.2 输入验证
c复制int read_int(const char *input) {
char *end;
long val = strtol(input, &end, 10);
if (end == input || *end != '\0' || errno == ERANGE) {
return -1; // 无效输入
}
return (int)val;
}
42. 编译器特定扩展
42.1 GCC属性语法
c复制// 冷热路径标记
void __attribute__((hot)) process_fast_path();
void __attribute__((cold)) process_error_case();
// 分支预测提示
if (__builtin_expect(condition, 1)) {
// 很可能执行的路径
}
42.2 MSVC特定扩展
c复制__declspec(align(16)) struct AlignedStruct {
int data[4];
};
__forceinline void critical_function();
43. 代码混淆技术
43.1 符号混淆
c复制// 编译时使用-fvisibility=hidden
__attribute__((visibility("default"))) void exported_func();
43.2 控制流混淆
c复制void (*funcs[])(void) = {func1, func2, func3};
funcs[rand() % 3]();
44. 调试信息管理
44.1 符号剥离
bash复制strip --strip-all program
44.2 调试符号分离
bash复制objcopy --only-keep-debug program program.debug
objcopy --strip-debug program
objcopy --add-gnu-debuglink=program.debug program
45. 构建优化技巧
45.1 链接时优化
bash复制gcc -flto -O3 file1.c file2.c -o program
45.2 预编译头文件
bash复制gcc -xc-header stdafx.h -o stdafx.h.gch
46. 代码覆盖率分析
46.1 gcov使用
bash复制gcc -fprofile-arcs -ftest-coverage program.c -o program
./program
gcov program.c
46.2 lcov可视化
bash复制lcov -c -d . -o coverage.info
genhtml coverage.info -o coverage_report
47. 二进制分析技巧
47.1 objdump反汇编
bash复制objdump -d program > disassembly.txt
47.2 nm符号查看
bash复制nm -C program > symbols.txt
48. 系统调用追踪
48.1 strace使用
bash复制strace -o trace.log ./program
48.2 ltrace库调用追踪
bash复制ltrace -o trace.log ./program
49. 内存布局分析
49.1 段信息查看
bash复制size program
49.2 内存映射分析
bash复制pmap -x <pid>
50. 高级调试技巧
50.1 反向调试
bash复制gdb --args program
(gdb) record
(gdb) reverse-step
50.2 观察点设置
bash复制(gdb) watch variable
(gdb) rwatch *0x12345678
(gdb) awatch global_var
51. 性能计数器使用
51.1 perf工具应用
bash复制perf stat ./program
perf record ./program
perf report
51.2 硬件计数器编程
c复制#include <linux/perf_event.h>
#include <sys/syscall.h>
static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
int cpu, int group_fd, unsigned long flags) {
return syscall(__NR_perf_event_open, hw_event, pid, cpu, group_fd, flags);
}
52. 内核模块开发
52.1 模块基本结构
c复制#include <linux/module.h>
static int __init my_init(void) {
printk(KERN_INFO "Module loaded\n");
return 0;
}
static void __exit my_exit(void) {
printk(KERN_INFO "Module unloaded\n");
}
module_init(my_init);
module_exit(my_exit);
MODULE_LICENSE("GPL");
52.2 内核内存分配
c复制#include <linux/slab.h>
void *kmem = kmalloc(size, GFP_KERNEL);
if (kmem) {
// 使用内存
kfree(kmem);
}
53. 用户空间与内核通信
53.1 proc文件系统
c复制// 内核模块中
static struct proc_dir_entry *ent;
static ssize_t my_read(struct file *file, char __user *ubuf, size_t count, loff_t *ppos) {
// 实现读取
}
static struct proc_ops pops = {
.proc_read = my_read,
};
ent = proc_create("myproc", 0666, NULL, &pops);
53.2 netlink套接字
c复制// 内核侧
struct sock *nl_sk = netlink_kernel_create(&init_net, NETLINK_USER, &cfg);
// 用户侧
struct sockaddr_nl src_addr, dest_addr;
int sock_fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_USER);
54. 实时系统编程
54.1 优先级设置
c复制#include <sched.h>
struct sched_param param = {
.sched_priority = 99
};
sched_setscheduler(0, SCHED_FIFO, ¶m);
54.2 内存锁定
c复制#include <sys/mman.h>
mlockall(MCL_CURRENT | MCL_FUTURE);
55. 信号量使用模式
55.1 命名信号量
c复制#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>
sem_t *sem = sem_open("/mysem", O_CREAT, 0644, 1
