printf是如何实现传任意多个参数
2026/8/24大约 2 分钟
C语言可变参数:printf 是怎么实现的
printf 能接收任意多个参数,是因为 C 语言提供了可变参数机制:
int printf(const char *fmt, ...);其中:
fmt → 固定参数
... → 任意多个参数一、自己写一个简单的可变参数函数
#include <stdio.h>
#include <stdarg.h>
void my_printf(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
while (*fmt)
{
if (*fmt != '%')
{
putchar(*fmt++);
continue;
}
fmt++;
switch (*fmt)
{
case 'd':
{
int x = va_arg(ap, int);
printf("%d", x);
break;
}
case 's':
{
char *s = va_arg(ap, char *);
printf("%s", s);
break;
}
case 'f':
{
double x = va_arg(ap, double);
printf("%f", x);
break;
}
}
fmt++;
}
va_end(ap);
}调用:
my_printf("num=%d, str=%s\n", 123, "hello");二、这几个宏分别干什么?
va_list
→ 保存遍历参数所需的状态
va_start
→ 初始化参数遍历
va_arg
→ 按指定类型取出下一个参数
va_end
→ 结束参数遍历例如:
va_arg(ap, int);意思是:
把下一个参数按
int类型取出来。
它不会自动判断类型。
三、printf 怎么知道参数类型?
靠的就是格式字符串:
printf("%d %s %f", 10, "hello", 3.14);printf 解析:
%d → 按 int 取
%s → 按 char * 取
%f → 按 double 取所以可以理解为:
格式字符串
↓
告诉 printf 参数是什么类型
↓
va_arg 按类型取参数四、格式错误为什么危险?
例如:
printf("%d", 3.14);格式字符串要求:
%d → int但实际传入:
3.14 → double于是:
实际类型
↓
double
printf
↓
按 int 取
结果
↓
未定义行为所以格式字符串和参数必须匹配。
五、为什么 %f 对应 double?
可变参数调用时存在默认参数提升:
float
↓
double因此:
float f = 3.14f;
printf("%f", f);传给 printf 的实际类型是:
double所以内部按:
va_arg(ap, double);获取。
六、真正的 printf
真实的 libc printf 远比上面的代码复杂,还涉及:
- 缓冲区
- 文件流
- 整数格式化
- 浮点格式化
- 字符串处理
- locale
- 底层输出
但核心思想就是:
printf(fmt, ...)
↓
解析 fmt
↓
遇到 %d / %s / %f
↓
va_arg 按对应类型取参数
↓
格式化
↓
输出
printf并不是“自动知道参数类型”,而是通过格式字符串告诉自己应该怎样解释后面的可变参数。

