C 语言高级编程指南:回调函数与设计模式

C 语言高级编程指南:回调函数与设计模式

目录

  1. 回调函数详解
  2. C语言中的设计模式
  3. 高级回调函数应用
  4. 内存管理与安全
  5. 多线程环境下的设计模式

回调函数详解

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;
}

设计模式的选择与应用

何时使用哪种设计模式?

是 否 单个 多个 是 否 是 否 状态变化通知 算法切换 命令封装 问题类型 创建对象? 单个或多个? 结构问题? 单例模式 工厂模式 接口适配? 行为问题? 适配器模式 组合模式 观察者模式 策略模式 命令模式

设计模式最佳实践
  1. 选择原则

    • 优先考虑简单解决方案
    • 确保模式能解决实际问题
    • 考虑维护成本和团队理解成本
  2. 实现建议

    • 保持接口简单明确
    • 注意内存管理
    • 考虑线程安全性
    • 提供完整的错误处理
  3. 常见应用场景

应用场景 配置管理 插件系统 事件处理 GUI开发 单例模式 工厂模式 观察者模式 组合模式

  1. 注意事项
    • 避免过度设计
    • 保持代码可测试性
    • 考虑性能影响
    • 确保线程安全
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. 尝试实现更多的设计模式
  2. 在实际项目中运用回调函数
  3. 练习内存管理和错误处理
  4. 研究标准库中的回调函数应用

记住:设计模式是工具而非目标,应该根据实际需求选择合适的模式,避免过度设计。

高级回调函数应用

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);
}

实用技巧与最佳实践

  1. 异步编程模式
  • 使用回调函数处理异步操作
  • 实现事件驱动架构
  • 处理超时和错误情况
  1. 内存管理策略
  • 使用智能指针模式
  • 实现资源获取即初始化(RAII)
  • 处理内存泄漏和悬挂指针
  1. 线程安全考虑
  • 正确使用互斥锁和条件变量
  • 避免死锁
  • 使用原子操作
  • 实现线程安全的数据结构
  1. 错误处理
  • 实现统一的错误处理机制
  • 使用错误回调
  • 合理处理异常情况
  1. 性能优化
  • 减少锁竞争
  • 使用无锁数据结构
  • 优化内存分配
  • 实现高效的缓存策略

调试技巧

  1. 使用断言验证invariants
  2. 实现日志系统
  3. 添加性能计数器
  4. 使用条件编译进行调试

记住:设计模式是工具而非目标,应该根据实际需求选择合适的模式,避免过度设计。在实际应用中,需要权衡性能、可维护性和复杂度,选择最适合的解决方案。

相关推荐
明月醉窗台12 分钟前
Qt 入门 1 之第一个程序 Hello World
开发语言·c++·qt
Craaaayon24 分钟前
Java八股文-List集合
java·开发语言·数据结构·list
幻想趾于现实30 分钟前
C# Winform 入门(11)之制作酷炫灯光效果
开发语言·c#·winform
hy____12335 分钟前
类与对象(中)(详解)
开发语言·c++
wen__xvn40 分钟前
c++STL入门
开发语言·c++·算法
2301_794461571 小时前
多线程编程中的锁策略
java·开发语言
University of Feriburg1 小时前
4-c语言中的数据类型
linux·c语言·笔记·学习·嵌入式实时数据库·嵌入式软件
XYN611 小时前
【嵌入式学习3】基于python的tcp客户端、服务器
服务器·开发语言·网络·笔记·python·学习·tcp/ip
小雅痞1 小时前
C语言--统计字符串中最长的单词
c语言
只有月亮知道1 小时前
C++list常用接口和模拟实现
开发语言·c++