C 语言高级编程指南:回调函数与设计模式
目录
回调函数详解
1. 什么是回调函数?
回调函数(Callback Function)是一个通过函数指针调用的函数。它允许将函数作为参数传递给另一个函数,实现了一种松耦合的编程方式。
2. 回调函数的基本语法
c
// 定义回调函数类型
typedef void (*callback_t)(int);
// 接受回调函数作为参数的函数
void process_with_callback(callback_t callback) {
// 执行一些操作
callback(42); // 调用回调函数
}
// 回调函数的实现
void my_callback(int value) {
printf("回调函数被调用,参数值:%d\n", value);
}
// 使用示例
int main() {
process_with_callback(my_callback);
return 0;
}
3. 回调函数的应用场景
3.1 事件处理
c
typedef struct {
void (*onClick)(void);
void (*onDoubleClick)(void);
} ButtonCallbacks;
typedef struct {
ButtonCallbacks callbacks;
char* label;
} Button;
void button_click(Button* btn) {
if (btn->callbacks.onClick) {
btn->callbacks.onClick();
}
}
3.2 数据处理
c
// 通用数组处理函数
void process_array(int* array, size_t size, void (*processor)(int*)) {
for (size_t i = 0; i < size; i++) {
processor(&array[i]);
}
}
// 具体的处理函数
void double_value(int* value) {
*value *= 2;
}
void square_value(int* value) {
*value = (*value) * (*value);
}
4. 回调函数进阶技巧
4.1 带上下文的回调
c
typedef void (*callback_with_context_t)(void* context, int value);
void process_with_context(callback_with_context_t callback, void* context) {
callback(context, 42);
}
typedef struct {
int multiplier;
} ProcessContext;
void process_callback(void* context, int value) {
ProcessContext* ctx = (ProcessContext*)context;
printf("结果:%d\n", value * ctx->multiplier);
}
C语言中的设计模式
设计模式概述
设计模式是软件开发中常见问题的典型解决方案。在C语言中,尽管没有面向对象的特性,我们仍然可以通过结构体和函数指针来实现这些模式。以下是最常用的几种设计模式及其实现。
C语言设计模式 创建型模式 结构型模式 行为型模式 单例模式 工厂模式 建造者模式 适配器模式 组合模式 代理模式 观察者模式 策略模式 命令模式
1. 单例模式(Singleton Pattern)
单例模式确保一个类只有一个实例,并提供一个全局访问点。
图解单例模式
客户端 单例对象 实例存储 1. 请求实例 get_instance() 2. 检查实例是否存在 2.1 返回 NULL 2.2 创建新实例 2.3 存储实例 2.1 返回现有实例 alt [实例不存在] [实例存在] 3. 返回实例 客户端 单例对象 实例存储
代码实现
c
typedef struct {
int data;
} Singleton;
static Singleton* instance = NULL;
Singleton* get_instance() {
if (instance == NULL) {
instance = (Singleton*)malloc(sizeof(Singleton));
instance->data = 0;
}
return instance;
}
2. 观察者模式(Observer Pattern)
观察者模式定义了对象之间的一对多依赖关系,使得当一个对象改变状态时,所有依赖于它的对象都会得到通知并自动更新。
图解观察者模式
Subject +observers: Observer[] +attach(Observer) +detach(Observer) +notify() Observer +update() ConcreteObserver +update()
Subject Observer1 Observer2 注册观察者 attach(observer1) attach(observer2) 状态改变 状态更新 notify() notify() update() update() Subject Observer1 Observer2
代码实现
c
#define MAX_OBSERVERS 10
typedef struct {
void (*update)(void* self, int data);
} Observer;
typedef struct {
Observer* observers[MAX_OBSERVERS];
int observer_count;
int data;
} Subject;
void subject_attach(Subject* subject, Observer* observer) {
if (subject->observer_count < MAX_OBSERVERS) {
subject->observers[subject->observer_count++] = observer;
}
}
void subject_notify(Subject* subject) {
for (int i = 0; i < subject->observer_count; i++) {
subject->observers[i]->update(subject->observers[i], subject->data);
}
}
3. 策略模式(Strategy Pattern)
策略模式定义了一系列算法,并使这些算法可以相互替换。策略模式使算法可以独立于使用它的客户端而变化。
图解策略模式
Context +strategy: Strategy +execute() <<interface>> Strategy +algorithm() ConcreteStrategyA +algorithm() ConcreteStrategyB +algorithm()
策略A 策略B 策略C 客户端 上下文Context 策略选择 加法策略 减法策略 乘法策略 执行策略
代码实现
c
typedef int (*Strategy)(int, int);
int add_strategy(int a, int b) { return a + b; }
int subtract_strategy(int a, int b) { return a - b; }
int multiply_strategy(int a, int b) { return a * b; }
typedef struct {
Strategy strategy;
} Context;
void set_strategy(Context* context, Strategy strategy) {
context->strategy = strategy;
}
int execute_strategy(Context* context, int a, int b) {
return context->strategy(a, b);
}
4. 工厂模式(Factory Pattern)
工厂模式提供了一种封装对象创建逻辑的方法,让客户端代码与具体类的实现解耦。
图解工厂模式
Factory +createProduct() <<interface>> Product +process() ConcreteProductA +process() ConcreteProductB +process()
客户端 工厂 产品 请求创建产品 根据类型选择产品 创建产品A 创建产品B alt [创建产品A] [创建产品B] 返回产品实例 客户端 工厂 产品
代码实现
c
typedef struct {
void (*process)(void);
} Product;
typedef struct {
void (*process)(void);
} ConcreteProductA;
typedef struct {
void (*process)(void);
} ConcreteProductB;
Product* create_product(char type) {
switch(type) {
case 'A':
return (Product*)malloc(sizeof(ConcreteProductA));
case 'B':
return (Product*)malloc(sizeof(ConcreteProductB));
default:
return NULL;
}
}
5. 命令模式(Command Pattern)
命令模式将请求封装成对象,从而使你可以用不同的请求对客户端参数化,实现请求的排队、记录日志等功能。
图解命令模式
Invoker +command: Command +execute() <<interface>> Command +execute() ConcreteCommand +receiver: Receiver +execute() Receiver +action()
客户端 调用者 命令 接收者 创建命令 设置命令 执行命令 调用接收者方法 执行完成 返回结果 客户端 调用者 命令 接收者
代码实现
6. 适配器模式(Adapter Pattern)
适配器模式允许将一个类的接口转换成客户端期望的另一个接口,使得原本不兼容的类可以一起工作。
图解适配器模式
<<interface>> Target +request() Adapter +adaptee: Adaptee +request() Adaptee +specificRequest()
客户端 适配器 被适配者 调用request() 转换调用specificRequest() 返回结果 转换并返回结果 客户端 适配器 被适配者
代码实现
c
// 被适配者
typedef struct {
void (*specificRequest)(void);
} Adaptee;
void adaptee_specific_request(void) {
printf("被适配者的特殊请求\n");
}
// 目标接口
typedef struct {
void (*request)(void);
} Target;
// 适配器
typedef struct {
Target target;
Adaptee* adaptee;
} Adapter;
void adapter_request(void* self) {
Adapter* adapter = (Adapter*)self;
// 转换调用
adapter->adaptee->specificRequest();
}
Adapter* create_adapter(Adaptee* adaptee) {
Adapter* adapter = malloc(sizeof(Adapter));
adapter->adaptee = adaptee;
adapter->target.request = adapter_request;
return adapter;
}
7. 组合模式(Composite Pattern)
组合模式允许你将对象组合成树形结构来表示"部分-整体"的层次结构,使得客户端可以统一处理单个对象和组合对象。
图解组合模式
Component +operation() +add(Component) +remove(Component) +getChild(int) Leaf +operation() Composite +children: Component[] +operation() +add(Component) +remove(Component) +getChild(int)
代码实现
c
typedef struct Component {
void (*operation)(struct Component*);
void (*add)(struct Component*, struct Component*);
void (*remove)(struct Component*, struct Component*);
struct Component* (*getChild)(struct Component*, int);
struct Component** children;
int childCount;
} Component;
// 叶子节点
void leaf_operation(Component* self) {
printf("叶子节点操作\n");
}
// 组合节点
void composite_operation(Component* self) {
printf("组合节点操作\n");
for (int i = 0; i < self->childCount; i++) {
self->children[i]->operation(self->children[i]);
}
}
void composite_add(Component* self, Component* child) {
self->children[self->childCount++] = child;
}
设计模式的选择与应用
何时使用哪种设计模式?
是 否 单个 多个 是 否 是 否 状态变化通知 算法切换 命令封装 问题类型 创建对象? 单个或多个? 结构问题? 单例模式 工厂模式 接口适配? 行为问题? 适配器模式 组合模式 观察者模式 策略模式 命令模式
设计模式最佳实践
-
选择原则
- 优先考虑简单解决方案
- 确保模式能解决实际问题
- 考虑维护成本和团队理解成本
-
实现建议
- 保持接口简单明确
- 注意内存管理
- 考虑线程安全性
- 提供完整的错误处理
-
常见应用场景
应用场景 配置管理 插件系统 事件处理 GUI开发 单例模式 工厂模式 观察者模式 组合模式
- 注意事项
- 避免过度设计
- 保持代码可测试性
- 考虑性能影响
- 确保线程安全
c
typedef struct {
void (*execute)(void);
} Command;
typedef struct {
Command* command;
} Invoker;
void invoker_set_command(Invoker* invoker, Command* command) {
invoker->command = command;
}
void invoker_execute_command(Invoker* invoker) {
if (invoker->command) {
invoker->command->execute();
}
}
最佳实践与注意事项
1. 回调函数注意事项
- 始终检查回调函数指针是否为 NULL
- 注意回调函数的生命周期管理
- 避免回调函数中的循环引用
- 合理使用上下文(context)传递数据
2. 设计模式使用建议
- 根据实际需求选择合适的设计模式
- 避免过度设计
- 注意内存管理和资源释放
- 保持代码的可维护性和可读性
实战示例:结合回调函数和观察者模式
c
#include <stdio.h>
#include <stdlib.h>
// 观察者接口
typedef struct Observer {
void (*update)(struct Observer* self, void* data);
void* context;
} Observer;
// 主题(Subject)
typedef struct {
Observer* observers[10];
int count;
int data;
} Subject;
// 初始化主题
void subject_init(Subject* subject) {
subject->count = 0;
subject->data = 0;
}
// 添加观察者
void subject_attach(Subject* subject, Observer* observer) {
if (subject->count < 10) {
subject->observers[subject->count++] = observer;
}
}
// 通知所有观察者
void subject_notify(Subject* subject) {
for (int i = 0; i < subject->count; i++) {
subject->observers[i]->update(subject->observers[i], &subject->data);
}
}
// 具体观察者实现
void console_observer_update(Observer* self, void* data) {
int* value = (int*)data;
printf("控制台观察者收到更新:%d\n", *value);
}
void file_observer_update(Observer* self, void* data) {
int* value = (int*)data;
printf("文件观察者收到更新:%d\n", *value);
}
int main() {
// 创建主题
Subject subject;
subject_init(&subject);
// 创建观察者
Observer console_observer = { console_observer_update, NULL };
Observer file_observer = { file_observer_update, NULL };
// 注册观察者
subject_attach(&subject, &console_observer);
subject_attach(&subject, &file_observer);
// 更新数据并通知
subject.data = 42;
subject_notify(&subject);
return 0;
}
总结
本指南详细介绍了 C 语言中的回调函数机制和常用设计模式。通过合理运用这些技术,可以编写出更加灵活、可维护的代码。建议读者多加练习,在实际项目中灵活运用这些概念。
进一步学习建议
- 尝试实现更多的设计模式
- 在实际项目中运用回调函数
- 练习内存管理和错误处理
- 研究标准库中的回调函数应用
记住:设计模式是工具而非目标,应该根据实际需求选择合适的模式,避免过度设计。
高级回调函数应用
1. 异步回调实现
c
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
typedef struct {
void (*callback)(void* data);
void* data;
} AsyncTask;
void* async_worker(void* arg) {
AsyncTask* task = (AsyncTask*)arg;
// 模拟耗时操作
sleep(2);
// 执行回调
task->callback(task->data);
free(task);
return NULL;
}
void execute_async(void (*callback)(void* data), void* data) {
AsyncTask* task = malloc(sizeof(AsyncTask));
task->callback = callback;
task->data = data;
pthread_t thread;
pthread_create(&thread, NULL, async_worker, task);
pthread_detach(thread);
}
// 使用示例
void on_complete(void* data) {
printf("异步任务完成,结果:%d\n", *(int*)data);
}
int main() {
int* value = malloc(sizeof(int));
*value = 42;
execute_async(on_complete, value);
printf("主线程继续执行...\n");
sleep(3); // 等待异步任务完成
return 0;
}
2. 链式回调
c
typedef struct ChainCallback {
void (*func)(void* data, struct ChainCallback* next);
struct ChainCallback* next;
void* data;
} ChainCallback;
void execute_chain(ChainCallback* chain) {
if (chain) {
chain->func(chain->data, chain->next);
}
}
// 示例回调函数
void step1(void* data, ChainCallback* next) {
printf("步骤1完成\n");
if (next) execute_chain(next);
}
void step2(void* data, ChainCallback* next) {
printf("步骤2完成\n");
if (next) execute_chain(next);
}
3. 事件循环与回调队列
c
#include <stdio.h>
#include <stdlib.h>
#define MAX_CALLBACKS 100
typedef struct {
void (*func)(void* data);
void* data;
} CallbackItem;
typedef struct {
CallbackItem items[MAX_CALLBACKS];
int head;
int tail;
} CallbackQueue;
void queue_init(CallbackQueue* queue) {
queue->head = queue->tail = 0;
}
void queue_push(CallbackQueue* queue, void (*func)(void*), void* data) {
if ((queue->tail + 1) % MAX_CALLBACKS != queue->head) {
queue->items[queue->tail].func = func;
queue->items[queue->tail].data = data;
queue->tail = (queue->tail + 1) % MAX_CALLBACKS;
}
}
int queue_pop(CallbackQueue* queue, CallbackItem* item) {
if (queue->head != queue->tail) {
*item = queue->items[queue->head];
queue->head = (queue->head + 1) % MAX_CALLBACKS;
return 1;
}
return 0;
}
void event_loop(CallbackQueue* queue) {
CallbackItem item;
while (1) {
if (queue_pop(queue, &item)) {
item.func(item.data);
}
// 可以添加适当的延时
}
}
内存管理与安全
1. 回调函数的内存安全
c
typedef struct {
void* data;
size_t data_size;
void (*cleanup)(void* data);
} SafeCallback;
void safe_callback_init(SafeCallback* cb, void* data, size_t size, void (*cleanup)(void*)) {
cb->data = malloc(size);
memcpy(cb->data, data, size);
cb->data_size = size;
cb->cleanup = cleanup;
}
void safe_callback_execute(SafeCallback* cb, void (*func)(void*)) {
if (cb && func) {
func(cb->data);
}
}
void safe_callback_cleanup(SafeCallback* cb) {
if (cb) {
if (cb->cleanup) {
cb->cleanup(cb->data);
} else {
free(cb->data);
}
cb->data = NULL;
cb->data_size = 0;
}
}
2. 引用计数与生命周期管理
c
typedef struct {
int ref_count;
void* data;
void (*destructor)(void*);
} RefCounted;
RefCounted* ref_counted_create(void* data, void (*destructor)(void*)) {
RefCounted* rc = malloc(sizeof(RefCounted));
rc->ref_count = 1;
rc->data = data;
rc->destructor = destructor;
return rc;
}
void ref_counted_acquire(RefCounted* rc) {
if (rc) {
__atomic_add_fetch(&rc->ref_count, 1, __ATOMIC_SEQ_CST);
}
}
void ref_counted_release(RefCounted* rc) {
if (rc) {
if (__atomic_sub_fetch(&rc->ref_count, 1, __ATOMIC_SEQ_CST) == 0) {
if (rc->destructor) {
rc->destructor(rc->data);
}
free(rc);
}
}
}
多线程环境下的设计模式
1. 线程安全的单例模式
c
#include <pthread.h>
typedef struct {
int data;
} Singleton;
static Singleton* volatile instance = NULL;
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
Singleton* get_thread_safe_instance() {
Singleton* tmp = instance;
if (tmp == NULL) {
pthread_mutex_lock(&mutex);
tmp = instance;
if (tmp == NULL) {
tmp = malloc(sizeof(Singleton));
tmp->data = 0;
instance = tmp;
}
pthread_mutex_unlock(&mutex);
}
return instance;
}
2. 生产者-消费者模式
c
#include <pthread.h>
#define BUFFER_SIZE 10
typedef struct {
void* buffer[BUFFER_SIZE];
int count;
int in;
int out;
pthread_mutex_t mutex;
pthread_cond_t not_full;
pthread_cond_t not_empty;
} BoundedBuffer;
void buffer_init(BoundedBuffer* bb) {
bb->count = 0;
bb->in = 0;
bb->out = 0;
pthread_mutex_init(&bb->mutex, NULL);
pthread_cond_init(&bb->not_full, NULL);
pthread_cond_init(&bb->not_empty, NULL);
}
void buffer_put(BoundedBuffer* bb, void* item) {
pthread_mutex_lock(&bb->mutex);
while (bb->count == BUFFER_SIZE) {
pthread_cond_wait(&bb->not_full, &bb->mutex);
}
bb->buffer[bb->in] = item;
bb->in = (bb->in + 1) % BUFFER_SIZE;
bb->count++;
pthread_cond_signal(&bb->not_empty);
pthread_mutex_unlock(&bb->mutex);
}
void* buffer_get(BoundedBuffer* bb) {
pthread_mutex_lock(&bb->mutex);
while (bb->count == 0) {
pthread_cond_wait(&bb->not_empty, &bb->mutex);
}
void* item = bb->buffer[bb->out];
bb->out = (bb->out + 1) % BUFFER_SIZE;
bb->count--;
pthread_cond_signal(&bb->not_full);
pthread_mutex_unlock(&bb->mutex);
return item;
}
3. 线程池模式
c
typedef struct {
void (*function)(void* arg);
void* arg;
} Task;
typedef struct {
Task* tasks;
int task_capacity;
int task_count;
int head;
int tail;
pthread_t* threads;
int thread_count;
pthread_mutex_t lock;
pthread_cond_t not_empty;
pthread_cond_t not_full;
int shutdown;
} ThreadPool;
ThreadPool* thread_pool_create(int thread_count, int task_capacity) {
ThreadPool* pool = malloc(sizeof(ThreadPool));
pool->tasks = malloc(sizeof(Task) * task_capacity);
pool->task_capacity = task_capacity;
pool->task_count = 0;
pool->head = 0;
pool->tail = 0;
pool->threads = malloc(sizeof(pthread_t) * thread_count);
pool->thread_count = thread_count;
pthread_mutex_init(&pool->lock, NULL);
pthread_cond_init(&pool->not_empty, NULL);
pthread_cond_init(&pool->not_full, NULL);
pool->shutdown = 0;
// 创建工作线程
for (int i = 0; i < thread_count; i++) {
pthread_create(&pool->threads[i], NULL, worker_thread, pool);
}
return pool;
}
void thread_pool_submit(ThreadPool* pool, void (*function)(void*), void* arg) {
pthread_mutex_lock(&pool->lock);
while (pool->task_count == pool->task_capacity && !pool->shutdown) {
pthread_cond_wait(&pool->not_full, &pool->lock);
}
if (pool->shutdown) {
pthread_mutex_unlock(&pool->lock);
return;
}
Task task = {function, arg};
pool->tasks[pool->tail] = task;
pool->tail = (pool->tail + 1) % pool->task_capacity;
pool->task_count++;
pthread_cond_signal(&pool->not_empty);
pthread_mutex_unlock(&pool->lock);
}
实用技巧与最佳实践
- 异步编程模式
- 使用回调函数处理异步操作
- 实现事件驱动架构
- 处理超时和错误情况
- 内存管理策略
- 使用智能指针模式
- 实现资源获取即初始化(RAII)
- 处理内存泄漏和悬挂指针
- 线程安全考虑
- 正确使用互斥锁和条件变量
- 避免死锁
- 使用原子操作
- 实现线程安全的数据结构
- 错误处理
- 实现统一的错误处理机制
- 使用错误回调
- 合理处理异常情况
- 性能优化
- 减少锁竞争
- 使用无锁数据结构
- 优化内存分配
- 实现高效的缓存策略
调试技巧
- 使用断言验证invariants
- 实现日志系统
- 添加性能计数器
- 使用条件编译进行调试
记住:设计模式是工具而非目标,应该根据实际需求选择合适的模式,避免过度设计。在实际应用中,需要权衡性能、可维护性和复杂度,选择最适合的解决方案。