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

运行结果:

<think>好的,用户想了解嵌入式C语言回调函数的写法、示例和应用场景。首先,我需要回忆回调函数的基本概念。回调函数是通过函数指针调用的函数,允许底层代码调用上层定义的函数,这在SDK开发中很常见,比如相机处理图像后的通知。 然后,结合用户提供的引用内容,特别是引用[1]和[2],回调函数用于异步通知,比如当A调用B的函数处理数据后,B通过回调A的函数来通知结果。引用[3]提到函数指针的灵活性和应用场景,如事件驱动架构。这需要具体例子来说明写法,比如如何定义函数指针和注册回调。 接下来,写法部分需要展示如何定义函数指针类型,如何实现回调函数,以及如何注册。例如,定义一个回调类型,然后在模块中保存该指针,并在特定事件发生时调用。示例代码需要简单明了,比如数据处理的回调,或者定时器触发。 应用场景部分,根据引用[2]和[3],可以列举SDK事件通知、异步操作、算法策略切换等。每个场景需要简短说明,比如相机获取图像后调用回调函数处理数据,或者根据不同策略动态切换函数。 还需要注意用户是嵌入式开发者,可能关注资源受限环境下的应用,因此强调回调函数在解耦和模块化方面的优势。同时,确保代码示例符合嵌入式C的常见实践,比如使用结构体传递数据,如引用[4]提到的结构体指针传递方式。 最后,检查是否符合系统级指令:行内公式用$,独立公式单独成段,中文回答,生成相关问题。确保LaTeX语法正确,但可能用户的问题中不涉及数学公式,所以可能不需要使用。不过如果有涉及变量或方程的地方,比如函数指针的声明,可能需要用行内格式,但C代码可能更适合用代码块。 生成的问题需要围绕回调函数的定义、应用、优缺点以及与其他技术的对比,帮助用户深入理解。</think>### 嵌入式C语言回调函数的定义与示例 #### 1. 回调函数定义方式 回调函数在嵌入式C语言中通过**函数指针**实现,分为以下三个步骤: - **定义函数指针类型**:指定回调函数的参数和返回值类型 例如:`typedef void (*CallbackFunc)(int status, void *user_data);` - **实现回调函数**:定义与函数指针类型匹配的具体函数 ```c void my_callback(int status, void *user_data) { printf("Status: %d, Data: %p\n", status, user_data); } ``` - **注册回调函数**:将函数指针传递给调用方 ```c void register_callback(CallbackFunc cb, void *data) { // 保存回调函数指针 g_callback = cb; g_user_data = data; } ``` #### 2. 完整示例代码 ```c #include <stdio.h> // 定义回调函数类型 typedef void (*DataProcessCallback)(const char *data, int len); // 数据处理模块 void data_processor(DataProcessCallback cb) { char buffer[] = "SensorData:25℃"; cb(buffer, sizeof(buffer)); // 触发回调 } // 具体回调实现 void log_callback(const char *data, int len) { printf("[LOG] %s\n", data); } int main() { data_processor(log_callback); // 注册回调 return 0; } ``` #### 3. 典型应用场景 1. **硬件事件通知** 如传感器数据到达时触发处理(引用[2]中的相机SDK案例) ```c // SDK提供注册回调接口 camera_register_callback(frame_ready_cb); ``` 2. **异步操作完成通知** 例如Flash写入完成后通过回调通知结果 3. **算法策略切换** 运行时动态选择加密算法(引用[3]的策略模式应用) ```c typedef void (*EncryptFunc)(uint8_t *data); EncryptFunc current_encrypt = aes_encrypt; // 可改为des_encrypt ``` #### 4. 优势与注意事项 - **优势**:解耦模块依赖、支持异步处理、增强扩展性[^3] - **注意事项**: - 使用`typedef`明确函数指针类型 - 通过`void*`传递上下文数据时需保证生命周期(引用[4]) - 避免在中断中执行复杂回调逻辑
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值