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. 使用条件编译进行调试

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

相关推荐
isyangli_blog1 小时前
OpenDayLight (Carbon 版本) 启动与组件安装
开发语言·php
vb2008111 小时前
FastAPI APIRouter
开发语言·python
Benszen1 小时前
KVM虚拟化解决方案
开发语言·perl
会编程的土豆1 小时前
Go 语言反射(Reflection)详解
开发语言·后端·golang
東雪木1 小时前
多线程与并发编程 专属复习笔记
java·开发语言·笔记·java面试
杨充2 小时前
1.3 浮点型数据设计灵魂
开发语言·python·算法
噜噜噜阿鲁~2 小时前
python学习笔记 | 11.3、面向对象高级编程-多重继承
java·开发语言
basketball6162 小时前
Go 语言从入门到进阶:4. 数组和MAP使用方法总结
开发语言·后端·golang
春生野草2 小时前
反射、Tomcat执行
java·开发语言
雪的季节3 小时前
企业级 Qt 全功能项目
开发语言·数据库·qt