/*
* 可变参数日志函数指针完整示例
* 演示如何注册和使用支持可变参数的日志函数
*/
// 标准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;
}
函数指针的使用方法
最新推荐文章于 2026-06-29 07:01:47 发布
1201

被折叠的 条评论
为什么被折叠?



