当前位置: 首页 > article >正文

C语言可变参数函数和可变参数宏

可变参数函数

在C语言中,可变参数函数(Variable Argument Function)是一种特殊的函数形式,它可以接受不定数量的参数。这类函数允许调用者在调用时传递任意数量的参数,这对于某些场景非常有用,例如日志记录、格式化输出等。

常见的可变参数函数

C语言标准库中有一些常用的可变参数函数,包括但不限于:

  • printf:格式化输出函数,可以接受不定数量的参数。
  • fprintf:向指定流格式化输出,可以接受不定数量的参数。
  • sprintf:将格式化输出写入到字符串中,可以接受不定数量的参数。
  • snprintf:将格式化输出写入到字符串中,指定最大长度,可以接受不定数量的参数。
  • vprintf:内部使用的可变参数格式化输出函数,通常不直接调用。
  • vfprintf:内部使用的可变参数格式化输出函数,通常不直接调用。
  • vsprintf:内部使用的可变参数格式化输出函数,通常不直接调用。
  • vsnprintf:内部使用的可变参数格式化输出函数,通常不直接调用。
  • scanf:从标准输入读取格式化输入,可以接受不定数量的参数。
  • fscanf:从指定流读取格式化输入,可以接受不定数量的参数。
  • sscanf:从字符串读取格式化输入,可以接受不定数量的参数。
可变参数函数的原理

在C语言中,可变参数函数依赖于两个宏定义:va_startva_listva_argva_end。这些宏定义定义在 <stdarg.h> 头文件中。它们的工作原理如下:

  1. va_list:定义一个类型为 va_list 的变量,用于保存可变参数列表的状态。
  2. va_start:宏 va_start 初始化 va_list 变量,准备从可变参数列表的第一个参数开始处理。
  3. va_arg:宏 va_arg 获取下一个参数,并返回该参数的值。
  4. va_end:宏 va_end 清理 va_list 变量。
可变参数函数的定义

可变参数函数的定义通常包含一个固定参数列表,后面跟着一个省略号 ...。省略号表示可以有任意数量的附加参数。

#include <stdarg.h>
#include <stdio.h>

// 定义一个可变参数函数
void __attribute__((format(printf,1,2))) my_printf(char *fmt,...)
{
	va_list args;
	va_start(args,fmt);
	vprintf(fmt,args);
	va_end(args);
}

int main() {
    my_printf("Hello, %s! Today is %s.\n", "world", "Monday");
    return 0;
}

运行结果:

Hello, world! Today is Monday.
可变参数函数实现日志系统

实现日志分级

#include <stdio.h>
#include <stdarg.h>

// 定义日志级别
typedef enum {
    LOG_LEVEL_DEBUG,
    LOG_LEVEL_INFO,
    LOG_LEVEL_WARNING,
    LOG_LEVEL_ERROR,
    LOG_LEVEL_NONE
} LogLevel;

// 编译时指定的日志级别,可以通过宏定义在编译时设置
#ifndef LOG_LEVEL
#define LOG_LEVEL LOG_LEVEL_DEBUG
#endif

// 日志函数
void __attribute__((format(printf,2,3))) DEBUG_PRINT(LogLevel level, const char *format, ...) {
    va_list args;
    const char *level_strings[] = {"DEBUG", "INFO", "WARNING", "ERROR"};

    if (level >= LOG_LEVEL) {
        va_start(args, format);
        printf("[%s] ", level_strings[level]);
        vprintf(format, args);
        printf("\n");
        va_end(args);
    }
}

// 示例使用
int main() {
    DEBUG_PRINT(LOG_LEVEL_DEBUG, "This is a debug message.");
    DEBUG_PRINT(LOG_LEVEL_INFO, "This is an info message.");
    DEBUG_PRINT(LOG_LEVEL_WARNING, "This is a warning message. %d, %s, %.2f, %d", 2, __func__, 3.14, __LINE__);
    DEBUG_PRINT(LOG_LEVEL_ERROR, "This is an error message.");

    return 0;
}

编译:

gcc main.c -DLOG_LEVEL=LOG_LEVEL_INFO

运行结果:

[INFO] This is an info message.
[WARNING] This is a warning message. 2, main, 3.14, 36
[ERROR] This is an error message.

可变参数宏

__VA_ARGS__

#include <stdio.h>
 
#define PRINT(...) printf(__VA_ARGS__)
 
int main() {
    int a = 10;
    char *str = "Hello, World!";
 
    PRINT("This is a normal message.\n");
    PRINT("a = %d, str = %s\n", a, str);
 
    return 0;
}

利用可变参数宏改造上面利用可变参数函数实现的日志系统

#include <stdio.h>
#include <stdarg.h>

// 定义日志级别
typedef enum {
    LOG_LEVEL_DEBUG,
    LOG_LEVEL_INFO,
    LOG_LEVEL_WARNING,
    LOG_LEVEL_ERROR,
    LOG_LEVEL_NONE
} LogLevel;

// 编译时指定的日志级别,可以通过宏定义在编译时设置
#ifndef LOG_LEVEL
#define LOG_LEVEL LOG_LEVEL_DEBUG
#endif

// 日志函数
void log_message(LogLevel level, const char *format, ...) {
    va_list args;
    const char *level_strings[] = {"DEBUG", "INFO", "WARNING", "ERROR"};

    if (level >= LOG_LEVEL) {
        va_start(args, format);
        printf("[%s] ", level_strings[level]);
        vprintf(format, args);
        printf("\n");
        va_end(args);
    }
}

// 定义宏,用于不同的日志级别
#define LOG_DEBUG(format, ...) log_message(LOG_LEVEL_DEBUG, format, ##__VA_ARGS__)
#define LOG_INFO(format, ...)  log_message(LOG_LEVEL_INFO, format, ##__VA_ARGS__)
#define LOG_WARNING(format, ...) log_message(LOG_LEVEL_WARNING, format, ##__VA_ARGS__)
#define LOG_ERROR(format, ...) log_message(LOG_LEVEL_ERROR, format, ##__VA_ARGS__)

// 示例使用
int main() {
    LOG_DEBUG("This is a debug message.");
    LOG_INFO("This is an info message.");
    LOG_WARNING("This is a warning message.");
    LOG_ERROR("This is an error message.");

    return 0;
}

编译:

gcc main.c -DLOG_LEVEL=LOG_LEVEL_INFO

运行结果:

[INFO] This is an info message.
[WARNING] This is a warning message.
[ERROR] This is an error message.

http://www.kler.cn/news/303161.html

相关文章:

  • Python 数学建模——方差分析
  • 无人机之伯努利定律
  • RabbitMQ消费者确认和重复机制
  • Python爬虫案例七:抓取南京公交信息数据并将其保存成excel多表形式
  • EXCEL导出功能——相关报错
  • 微信小程序开发注意事项
  • 通过mqtt通信远程控制大疆无人机
  • Java 学习路线:语言、框架、中间件与数据库
  • 【RabbitMQ】RabbitMQ如何保证数据的可靠性,RabbitMQ如何保证数据不丢失,数据存储
  • 手机玩机常识-------诺基亚系列机型3/5/6/7/8详细的刷机教程步骤 手机参考救砖刷机教程
  • Linux+Docker:3分钟实现MinIO在线部署与Java集成
  • 性能测试的复习3-jmeter的断言、参数化、提取器
  • 240909-ChuanhuChatGPT集成Ollama的环境配置
  • 卷积神经网络经典模型架构简介
  • 中国电子学会202406青少年软件编程(Python)等级考试试卷(三级)真题与解析
  • Linux(5)--CentOS8使用yum
  • 【Vue】- Vue表达式
  • 【漏洞复现】科荣AIO moffice Sql注入漏洞
  • 【HarmonyOS】Beta最新对外版本IDE下载和环境配置
  • 如何在Windows10系统安装docker?
  • Springboot引入通义千文大模型API
  • 前端代码规范- Commit 提交规范
  • linux-L10.查看你硬盘容量
  • OpenAI「草莓」两周内发布?网传不是多模态,反应慢了10多秒
  • docker 多服务只暴露一个客户端
  • 003InputSystem新输入系统学习工作笔记
  • R和Python数据格式的通用性
  • Mysql | 知识 | 事务隔离级别
  • netty之NioEventLoop和NioEventLoopGroup
  • 统计信息的导出导入