(const char *format, ...) 可变参数在文本日志中的巧妙使用

1. va_list是C语言中的一个数据类型,用于处理可变参数列表。它通常与stdarg.h头文件一起使用,该头文件提供了一组宏和函数来处理可变参数。

va_list类型用于存储一系列类型未知的参数,这些参数可以是任意类型,包括整数、浮点数、字符和指针等。它是一个结构体类型,通常在实现可变参数函数时定义。

使用va_list和相关的宏,可以实现在函数调用时动态地指定参数的数量和类型。这使得函数能够接受可变数量的参数,并且能够处理不同类型的参数。这种机制使得在函数定义时无需预先指定参数的类型和数量,提供了更大的灵活性和便利性。

2. va_start的实现方式是依赖于具体的编译器和平台的 。在大多数情况下,va_start的实现是编译器相关的,并依赖于平台上的寄存器或者其他机制来传递参数。

在大多数情况下,编译器会将可变参数列表存储在内存中的某个位置,然后使用特定的寄存器或者指针来引用该位置。va_start的作用就是初始化这个寄存器或者指针,以便后续的va_arg宏可以正确地获取参数。

具体来说,va_start会执行以下操作:

  1. 确定可变参数列表的起始位置。这个位置通常是由函数调用约定确定的,例如在C语言中,可变参数列表通常存储在栈帧中的某个特定位置。
  2. 初始化一个va_list类型的变量,该变量用于存储参数列表的当前位置。这个变量通常是一个结构体或者一组寄存器,具体取决于编译器和平台。
  3. 设置参数列表的初始位置,以便后续的va_arg宏可以正确地获取参数。这通常涉及到将参数列表的起始位置和当前位置信息存储到va_list类型的变量中。

一旦va_start被调用,就可以使用va_arg宏从参数列表中获取参数,直到所有参数都被获取完毕。最后,需要调用va_end宏来清理参数列表相关的资源。

  1. va_arg() 用于从可变参数列表中获取一个参数。va_arg() 宏接受两个参数:va_list 类型的变量和一个类型。它会将可变参数列表中的下一个参数转换为一个指向给定类型的指针,并返回该指针的值。例:

    void print_numbers(int n, ...) {
    va_list args;
    va_start(args, n);

    复制代码
     for (int i = 0; i < n; i++) {  
         int value = va_arg(args, int);  
         printf("%d ", value);  
     }  
    
     va_end(args);  

    }

4. va_end()是一个宏,用于清理使用va_start()宏开始的可变参数列表 。例如在函数接受可变数量的参数时,需要使用va_start()宏来开始参数列表,然后使用va_arg()宏来获取参数。一旦处理完所有参数,应该使用va_end()宏来清理参数列表。

va_end()宏会释放由va_start()宏分配的内存,并确保参数列表正确终止。如果不调用va_end()宏,可能会导致内存泄漏或其他问题。

  1. 通过可变参数函数我们可以实现类似于printf函数的日志上报函数:

    /// @brief 添加带数据的日志内容
    /// @param format
    /// @param
    void model_log_add_data(const char *format, ...)
    {
    // return_if_fail(stModel_log_page.inited == 1);
    OS_ERR err;
    OSMutexPend(&stModel_log_page.mutex, 0, OS_OPT_PEND_BLOCKING, NULL, &err);

    复制代码
     va_list args;
     va_start(args, format);
    
     static char buffer[256];
     vsnprintf(buffer, sizeof(buffer), format, args);
     buffer[sizeof(buffer) - 1] = '\0';
     int len = strlen(buffer);
    
     return_if_fail(len < MODEL_LOG_DATA_LEN);
    
     if (stModel_log_page.len + len > MODEL_LOG_DATA_LEN)
     {
     	model_log_report();
     	model_log_data_init();
     }
    
     strcat(stModel_log_page.data, buffer);
     // printf("%s\r\n", stModel_log_page.data);
     stModel_log_page.len += len;
    
     va_end(args);
    
     OSMutexPost(&stModel_log_page.mutex, OS_OPT_PEND_BLOCKING, &err);

    }

相关推荐
深圳市宝华视联13 分钟前
Python 读取 IP 视频流简单 Demo
python·嵌入式硬件·opencv·网络协议·tcp/ip·实时音视频·嵌入式实时数据库
恒锐丰科技韩生37 分钟前
RB6005A|晶准 单节锂电池内置 MOS 保护芯片 DFN2×3‑8
嵌入式硬件·硬件工程
youshi66681 小时前
stm32-PWR、低功耗模式
stm32·单片机·嵌入式硬件
ACP广源盛139246256731 小时前
Qwen3.8‑2.4T 开源落地@ACP#国产 Serdes 长距离视频传输芯片 GSV5800 在私有化 AI 服务中的价值与应用场景
大数据·数据库·人工智能·嵌入式硬件·矩阵·开源·音视频
Funing71 小时前
STM32 电机动态 PI 控制:从编码器反馈、增量式 PI 到 Matlab 参数拟合与 PWM 输出
stm32·嵌入式硬件·matlab·pi控制算法
Yyyyyy~1 小时前
【C语言】数据类型和变量【下】
c语言
云泽8082 小时前
深入浅出 STM32(十八):时钟树、总线与寄存器的底层联动机制
stm32·单片机·嵌入式硬件
米饭不加菜3 小时前
C51 语言参考手册
经验分享·笔记·单片机·嵌入式硬件
深圳市宝华视联3 小时前
院感约束下,手术室音视频布线与设备摆放实施注意事项
嵌入式硬件·音视频·实时音视频·视频编解码·嵌入式实时数据库
小雪崩3 小时前
嵌入式学习 day30:minilog
linux·c语言·学习