C语言——回调函数

目录

1、什么是回调函数

2、回调函数的作用

2.1. 事件驱动编程​​

2.2. 硬件中断处理​​

2.​​3. 异步通信协议​​

2.​​4. 定时器管理​​

3、回调函数示例 


1、什么是回调函数

        函数指针的调用,即是一个通过函数指针调用的函数

        如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,就说这是回调函数。

        把一段可执行的代码像参数传递那样传给其他代码,而这段代码会在某个时刻被调用执行,就叫做回调。如果代码立即被执行就称为同步回调,如果在之后晚点的某个时间再执行,则称为异步回调。

#include <stdio.h>

// 回调函数类型定义
typedef void (*Callback)(int);
/*
​​typedef 的作用​​它是在定义一个新类型(别名),而不是简单的“A 是 B 的别名”
    这里定义的类型是 ​​函数指针类型​​,不是普通的数据类型
​​(*Callback)(int) 的解析​​
    *Callback:这是一个指针变量(名称是 Callback)
    (int):它指向的函数接受一个 int 参数
    void:函数的返回类型是 void
    整体合起来:Callback 是一个 ​​指向函数的指针类型​​
*/

// 接收回调函数作为参数的函数
void processNumbers(int arr[], int size, Callback callback) {
    for (int i = 0; i < size; i++) {
        callback(arr[i]);  // 调用回调函数
    }
}

// 实际的回调函数实现
void printNumber(int num) {
    printf("Number: %d\n", num);
}

void squareNumber(int num) {
    printf("Square: %d\n", num * num);
}

int main() {
    int numbers[] = {1, 2, 3, 4, 5};
    int size = sizeof(numbers) / sizeof(numbers[0]);
    
    printf("Printing numbers:\n");
    // 为什么不需要给函数传递参数?,其实 printNumber 这个地方只需要提供一个地址,还没调用
    // processNumbers(numbers, size, printNumber());是错误写法
    processNumbers(numbers, size, printNumber);
    
    printf("\nPrinting squares:\n");
    processNumbers(numbers, size, squareNumber);
    
    return 0;
}

运行结果:

2、回调函数的作用

        回调函数的核心作用是 ​解耦 ​和​ 异步响应事件 ​,尤其在资源受限、实时性要求高的嵌入式环境中非常实用。以下是其具体作用和应用场景:

2.1. 事件驱动编程​

嵌入式系统常基于事件驱动(如按键、定时器、传感器数据到达),回调函数允许开发者:
  • ​将事件处理逻辑分离​​:主程序无需轮询检查事件,由底层驱动在事件发生时自动调用预设的回调函数。
  • ​示例​​:
  • // 注册按键回调
    void button_pressed_callback(void) {
        printf("Button pressed!\n");
    }
    
    // 驱动层在检测到按键时调用回调
    register_button_callback(button_pressed_callback);

2.2. 硬件中断处理​​

在中断服务例程(ISR)中,回调函数可以:
  • ​缩短中断处理时间​​:ISR仅做紧急操作(如清除标志位),后续逻辑通过回调函数在非中断上下文中执行。
  • ​避免中断嵌套问题​​:将耗时操作移出ISR。
  • ​示例​​:
  • void data_received_callback(uint8_t data) {
        // 处理接收到的数据(非中断上下文)
    }
    
    // UART中断中调用回调
    void USART1_IRQHandler(void) {
        if (RXNE_flag_set()) {
            uint8_t data = USART1->DR;
            data_received_callback(data); // 触发回调
        }
    }

2.​​3. 异步通信协议​

在UART、I2C、SPI等通信中:
  • ​非阻塞处理数据​​:发送/接收完成后通过回调通知应用层。
  • ​示例​​(伪代码):
  • void i2c_transfer_done_callback(bool success) {
        if (success) printf("Transfer completed!\n");
    }
    
    // 异步发送数据
    i2c_send_async(data, length, i2c_transfer_done_callback);

2.​​4. 定时器管理​

定时器超时或PWM周期结束时,回调函数用于:
  • ​执行周期性任务​​(如数据采集、LED闪烁)。
  • ​示例​​(使用硬件定时器):
  • void timer_callback(void) {
        static int count = 0;
        count++;
        if (count >= 10) turn_off_led();
    }
    
    // 初始化定时器并注册回调
    HAL_TIM_RegisterCallback(&htim, TIM_IT_UPDATE, timer_callback);

  • 3、回调函数示例 

        C语言的 qsort 函数,实现了一个冒泡排序算法,它既能从小到大排序,也能从大到小排序,取决与最后一个参数。

#include <stdio.h>

void sort(int a[], int size, int (*p)(int, int)){
    int i, j;
    for (i = 0; i < size - 1; i++){
        for (j = 0; j < size - 1 - i; j++){
            if (p(a[j], a[j + 1]))  {
                int t = a[j];
                a[j] = a[j + 1];
                a[j + 1] = t;
            }
        }
    }
}

int less(int x, int y){
    return (x > y) ? 1 : 0;
}

int greater(int x, int y){
    return (x < y) ? 1 : 0;
}

int main(){
    int a[10] = {1, 0, 4, 7, 2, 9, 5, 3, 8, 6};
    sort(a, 10, greater);//大到小排序
    for (int i = 0; i < 10; i++){
        printf("%d ", a[i]);
    }
    printf("\n");
    sort(a, 10, less);//小到大排序
    for (int i = 0; i < 10; i++){
        printf("%d ", a[i]);
    }
    return 0;
}

运行结果:

### C语言实现串口回调函数解析接收数据方法 在嵌入式开发中,利用回调函数可以有效地处理串口接收到的数据。这种方式不仅提高了代码的灵活性和可维护性,还使得程序结构更加清晰。 #### 定义回调函数原型 首先定义一个用于处理接收到的数据帧的回调函数原型。该函数接受两个参数:一个是缓冲区地址;另一个是接收到的有效字节数量[^3]。 ```c // 声明回调函数类型 typedef void (*FrameHandler)(uint8_t *buffer, size_t length); ``` #### 初始化串口并注册回调 接着,在初始化串口通信时指定上述类型的函数作为事件处理器。每当有新消息到达时就会自动触发此函数执行相应操作[^1]。 ```c void setup_uart(FrameHandler handler) { // 配置UART硬件... // 设置中断服务例程或其他机制以调用handler当有可用字符时 } ``` #### 编写具体业务逻辑 最后一步就是根据实际应用场景编写具体的业务逻辑了。这通常意味着要分析每一帧的内容,并据此采取适当的动作——可能是更新状态机、记录日志或是向其他设备转发信息等等[^4]。 ```c void process_frame(uint8_t *data, size_t len) { static uint8_t frame_buffer[FRAME_MAX_SIZE]; static size_t buffer_pos = 0; for (size_t i = 0; i < len; ++i) { if (is_start_of_frame(data[i])) { // 判断是否为起始标志 buffer_pos = 0; } else if (is_end_of_frame(data[i]) && buffer_pos > 0) { // 结束标志且非空 memcpy(frame_buffer + buffer_pos++, &data[i], sizeof(data[i])); // 处理完整的一帧数据 handle_complete_frame(frame_buffer, buffer_pos); buffer_pos = 0; // 清除位置准备下一个周期 } else if(buffer_pos < FRAME_MAX_SIZE){ memcpy(frame_buffer + buffer_pos++, &data[i], sizeof(data[i])); } } } setup_uart(process_frame); // 注册process_frame作为回调函数 ``` 通过以上步骤可以在C语言环境中成功地实现了基于回调机制的串口数据解析方案。这种方法能够显著简化复杂系统的构建过程,同时也提供了更好的性能表现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值