C语言 可变参数 函数间传递

本文介绍了一个自定义的`MyPrintf`函数,用于实现类似`printf`的功能,同时结合宏定义`LOG`实现日志级别控制。在`main`函数中,通过`LOG`宏展示了不同级别的日志输出,提供了一种简单的日志记录机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

typedef unsigned int u32;

// void printf(const char *fmt, ...)

void MyPrintf(u32 level, const char *pFunName, u32 line, const char *fmt, ...)
{
    char buf[256];
    va_list ap;

	if (level < 1) {
        return;
    }

    va_start(ap, fmt);
    vsnprintf(buf, sizeof(buf), fmt, ap);
    va_end(ap);

    printf("[%u %s %u] %s", level, pFunName, line, buf);
}


#define LOG(level, format, ...) MyPrintf(level, __FUNCTION__, __LINE__, format"\r\n", ##__VA_ARGS__)

int main()
{
	char *myName0 = "Super Man 0";
	char *myName1 = "Super Man 1";
	char *myName2 = "Super Man 2";
	
   	printf("Hello, World! \n");
	
	LOG(0, "Hello, %s", myName0);
	LOG(1, "Hello, %s", myName1);
	LOG(2, "Hello, %s", myName2);
   
   return 0;
}

执行结果:
Hello, World! 
[1 main 36] Hello, Super Man 1
[2 main 37] Hello, Super Man 2

<think>好的,用户想了解C语言中如何实现和使用可变参数函数,特别是va_list的示例。首先,我需要回顾相关知识,确保准确无误。根据提供的引用资料,可变参数函数在C语言中通过va_list系列宏实现,包括va_start、va_arg、va_end和va_copy。这些宏定义在stdarg.h头文件中。 用户可能需要一个清晰的步骤说明,所以应该分步骤讲解。首先,函数声明需要至少一个固定参数,然后是省略号表示可变参数。例如,函数声明为void func(int a, ...)。接下来,在函数内部使用va_list类型的变量来管理参数,比如va_list ap。 然后,使用va_start初始化ap,使其指向第一个可变参数。例如,va_start(ap, a)。这里需要注意,va_start的第二个参数是最后一个固定参数,这样它才能确定可变参数的起始位置。 接下来,使用va_arg逐个读取参数。需要指定参数的类型,例如int num = va_arg(ap, int);。这一步需要用户知道参数的类型和顺序,否则会导致错误。因此,在可变参数函数中,通常需要某种方式(如格式字符串)来确定参数的类型和数量,就像printf那样。 最后,使用va_end清理,确保资源正确释放,va_end(ap);。 用户可能还需要示例代码来更好地理解。根据引用中的示例,可以构造一个简单的函数,比如计算可变数量整数的平均值。示例中需要处理参数的数量,可能需要固定参数来传递数量,或者在参数列表末尾使用标记值。例如,函数average的第一个参数是数量,后面是可变数量的整数。 一个示例可以模仿printf,使用格式字符串来解析不同类型的参数,这需要用到vsnprintf等函数,如引用[2]中的示例。这里可能需要更复杂的处理,但用户可能更关注基础用法,所以先展示简单的例子,再提及高级应用。 还需要注意常见错误,比如忘记调用va_start或va_end,或者错误指定参数类型。例如,如果用户传递的是double,但用va_arg(ap, int)读取,会导致错误。此外,可变参数函数缺乏类型安全检查,容易出错,需要谨慎使用。 用户可能还想知道可变参数的应用场景,比如实现日志函数、调试输出或自定义的格式化函数。引用中提到的printf就是典型例子,还有需要处理不定数量参数的通用函数。 总结回答结构:先介绍概念和必要头文件,然后分步骤说明实现方法,给出简单示例和复杂示例,指出注意事项,最后总结应用场景。这样用户能逐步理解并应用可变参数函数。</think>### C语言可变参数函数的实现与用法 在C语言中,**可变参数函数**允许函数接收不定数量的参数,例如标准库函数`printf`和`scanf`。这类函数通过`va_list`系列宏(定义在`stdarg.h`头文件中)实现,具体步骤如下: --- #### 1. 基本实现步骤 1. **函数声明**: 函数需至少包含一个固定参数,后接`...`表示可变参数,例如: ```c void func(int a, ...); ``` 2. **初始化`va_list`**: 使用`va_start`初始化`va_list`指针,使其指向第一个可变参数: ```c va_list ap; // 定义可变参数指针 va_start(ap, a); // ap指向第一个可变参数(a是最后一个固定参数) ``` 3. **读取参数**: 通过`va_arg`按顺序读取参数,需指定参数类型: ```c int num = va_arg(ap, int); // 读取一个int类型参数 double val = va_arg(ap, double); // 读取一个double类型参数 ``` 4. **清理资源**: 使用`va_end`释放`va_list`相关资源: ```c va_end(ap); ``` --- #### 2. 示例:计算可变数量整数的平均值 ```c #include <stdarg.h> #include <stdio.h> double average(int count, ...) { va_list ap; va_start(ap, count); // ap指向count后的第一个参数 double sum = 0; for (int i = 0; i < count; i++) { sum += va_arg(ap, int); // 逐个读取int类型参数 } va_end(ap); return sum / count; } int main() { printf("平均值: %.2f\n", average(3, 10, 20, 30)); // 输出20.00 return 0; } ``` --- #### 3. 示例:模仿`printf`的格式化输出 ```c #include <stdarg.h> #include <stdio.h> void my_printf(const char *fmt, ...) { va_list ap; va_start(ap, fmt); // ap指向fmt后的第一个参数 vprintf(fmt, ap); // 直接调用vprintf处理格式化输出 va_end(ap); } int main() { my_printf("整数: %d, 字符串: %s\n", 42, "Hello"); // 输出整数: 42, 字符串: Hello return 0; } ``` --- #### 4. 注意事项 1. **类型安全**: 可变参数函数缺乏类型检查,若实际参数类型与`va_arg`指定的类型不符,会导致未定义行为[^3]。 2. **参数数量**: 需通过固定参数或特殊标记(如`NULL`)明确参数数量,否则可能访问无效内存[^4]。 3. **平台兼容性**: `va_list`的实现依赖编译器和平台,跨平台代码需谨慎[^1]。 --- #### 5. 应用场景 - 实现格式化输出(如`printf`)或输入(如`scanf`)[^2]。 - 自定义日志函数,支持动态参数。 - 泛型数据处理函数(如求最大值、最小值等)。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

洲游

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

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

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

打赏作者

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

抵扣说明:

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

余额充值