自学内容网 自学内容网

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.

原文地址:https://blog.csdn.net/qq_23905237/article/details/142209178

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!