函数指针的使用方法

/*
 * 可变参数日志函数指针完整示例
 * 演示如何注册和使用支持可变参数的日志函数
 */

// 标准C输入输出头文件,提供printf等函数
// 注意:C++中更常用<cstdio>,但<stdio.h>在C和C++中都可用
#include <stdio.h>

// C标准可变参数处理头文件
// 注意:在C++中,使用<cstdarg>(标准命名空间)和<stdarg.h>(全局命名空间)均可
// 这里使用C风格的<stdarg.h>以保持一致性
#include <stdarg.h>

/* 
 * LOGFUN: 函数指针类型定义
 * 指向一个接受以下参数的函数:
 *   int level        - 日志级别(整数)
 *   char const*      - 格式化字符串(常量字符指针,内容不可修改)
 *   ...              - 可变数量的参数(类似printf的可变参数机制)
 * 返回类型:void(无返回值)
 * 
 * 此类型定义了日志回调函数的统一接口,使不同的日志实现可以互换
 */
typedef void (*LOGFUN)(int level, char const*, ...);

//全局日志函数指针变量
LOGFUN log_fun = NULL;

/* 
 * log_register: 日志函数注册器
 * 参数:fun - 要注册的日志函数指针(类型为LOGFUN)
 * 功能:将传入的函数指针赋值给全局变量log_fun
 *       使后续代码可以通过log_fun调用已注册的日志函数
 * 
 * 注意:此函数不检查重复注册或NULL参数
 *       在实际应用中可能需要添加相应的错误处理逻辑
 */
void log_register(LOGFUN fun){
    // 简单地将传入的函数指针赋值给全局变量
    // 后续调用log_fun时,实际上会调用这里注册的函数
    log_fun = fun;
}

/* 
 * test_fun: 测试用的日志函数实现
 * 参数:
 *   level   - 日志级别(整数,表示日志的严重程度或类别)
 *   format  - 格式化字符串(类似printf的第一个参数)
 *   ...     - 可变数量的参数,与format配合使用
 * 
 * 功能:打印带级别的格式化日志消息到标准输出
 * 
 * 实现细节:
 * 1. 首先打印日志级别(用方括号括起来)
 * 2. 然后使用vprintf函数处理格式化字符串和可变参数
 * 3. 最后打印换行符
 * 
 * 优点:
 * - 支持完整的printf格式化语法
 * - 可以处理任意数量和类型的参数
 * 
 * 示例调用:
 *   test_fun(1, "Hello, %s!", "World");  // 输出: [Level 1]: Hello, World!
 *   test_fun(2, "Value: %d, Name: %s", 42, "Alice");  // 输出: [Level 2]: Value: 42, Name: Alice
 */
void test_fun(int level, char const* format, ...)
{
    // 1. 打印日志级别前缀
    //    使用固定的格式"[Level X]: ",其中X是日志级别
    printf("[Level %d]:", level);
    
    // 2. 处理可变参数
    //    va_list: 可变参数列表类型,用于存储可变参数的信息
    va_list args;           // 声明一个va_list变量
    
    //    va_start: 初始化args,使其指向format后的第一个可变参数
    //    注意:format必须是函数参数列表中的最后一个固定参数
    va_start(args, format);
    
    //    vprintf: 功能与printf类似,但接受va_list而不是可变参数列表
    //    根据format字符串格式化并打印可变参数
    vprintf(format, args);  // 使用vprintf处理可变参数
    
    //    va_end: 清理va_list,结束可变参数的访问
    //    这是一个必需的步骤,确保资源正确释放
    va_end(args);
    
    // 3. 打印换行符,使每条日志独占一行
    printf("\n");
}

/* 
 * main: 程序入口函数
 * 功能:演示日志函数指针的注册和调用过程
 */
int main()
{
    // 1. 将test_fun函数赋值给临时函数指针变量
    //    这一步不是必需的,可以直接传递test_fun给log_register
    //    但这样写更清晰地展示了函数指针的赋值操作
    LOGFUN temp_fun = test_fun;
    
    // 2. 注册日志函数
    //    将test_fun函数的地址存储到全局变量log_fun中
    //    之后可以通过log_fun调用test_fun
    log_register(temp_fun);
    
    // 3. 检查日志函数是否成功注册(log_fun不为NULL)
    //    这是一个良好的编程习惯,避免调用空指针导致程序崩溃
    if(log_fun){
        // 4. 通过函数指针调用已注册的日志函数
        //    注意:这里使用了log_fun而不是直接调用test_fun
        //    这提供了灵活性,可以随时更换日志实现而不修改调用代码
        
        //    示例1:简单的字符串日志
        //    参数:级别1,字符串"hello"
        //    预期输出:[Level 1]: hello
        log_fun(1, "hello");
        
        //    示例2:另一个简单的字符串日志
        //    参数:级别2,字符串"cakjwckaj"
        //    预期输出:[Level 2]: cakjwckaj
        log_fun(2, "hello %s","10");
        
        // 注意:上面的调用只传递了字符串,没有使用格式化功能
        // 但实际上test_fun支持printf风格格式化,例如:
        // log_fun(3, "User %s has %d messages", "Alice", 5);
        // 预期输出:[Level 3]: User Alice has 5 messages
    }
    
    // 返回0表示程序正常退出
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

10710

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值