详细解析 minprintf
的最小实现
Link: https://www.amazon.com/Programming-Language-2nd-Brian-Kernighan/dp/0131103628
翻看这本书,找寻printf的实现,书中给出一个最小实现,下面解析之。
这是C语言之父写的书
丹尼斯·麦卡利斯泰尔·里奇(英语:Dennis MacAlistair Ritchie,1941年9月9日—2011年10月12日),美国计算机科学家。黑客圈子通常称他为“dmr”[4]。他是C语言的创造者、Unix操作系统的关键开发者[5][6][7][8],对计算机领域产生了深远影响,并与肯·汤普逊同为1983年图灵奖得主。https://zh.wikipedia.org/wiki/%E4%B8%B9%E5%B0%BC%E6%96%AF%C2%B7%E9%87%8C%E5%A5%87
代码展示了一个简化版的 printf
函数实现,名为 minprintf
,能够处理有限的格式化输出功能,包括整数 (%d
)、浮点数 (%f
) 和字符串 (%s
)。以下是对代码的逐步解析,并特别关注 *++p
的语法。
代码核心功能
void minprintf(char *fmt, ...) {
va_list ap;
char *p, *sval;
int ival;
double dval;
va_start(ap, fmt); // 初始化可变参数列表
for (p = fmt; *p; p++) { // 遍历格式化字符串
if (*p != '%') { // 如果不是格式说明符,直接输出字符
putchar(*p);
continue;
}
switch (*++p) { // 获取格式说明符
case 'd':
ival = va_arg(ap, int); // 提取 int 参数
printf("%d", ival);
break;
case 'f':
dval = va_arg(ap, double); // 提取 double 参数
printf("%f", dval);
break;
case 's':
for (sval = va_arg(ap, char *); *sval; sval++) // 输出字符串
putchar(*sval);
break;
default:
putchar(*p); // 如果不是已知格式说明符,直接输出
break;
}
}
va_end(ap); // 清理可变参数
}
重点语法解析:*++p
在代码中,*++p
是一个关键的语法结构,其作用是:
++p
:将指针p
向前移动一个字符,指向下一个位置。*++p
:解引用新位置的字符,即获取格式说明符。
完整流程:
- 如果当前字符为
'%'
,通过++p
跳过'%'
,检查其后面的格式说明符(如'd'
、'f'
、's'
等)。 - 解引用
*++p
获取格式说明符,用于switch
语句处理。
示例与分析
假设有如下调用:
minprintf("Value: %d, Name: %s, Score: %f\n", 42, "Alice", 95.5);
1. 处理流程
p = "Value: %d, Name: %s, Score: %f\n"
(fmt
的内容)- 遍历字符串,遇到普通字符(如
'V'
、'a'
等)时,直接输出。 - 遇到
'%'
时,调用*++p
获取后续格式说明符并处理。
2. *++p
语法的作用
- 当
p
指向'%'
时:++p
将指针移动到下一位置,即'd'
。*++p
解引用,返回'd'
,交由switch
处理。
- 以此类推,后续会分别处理
'%s'
和'%f'
。
3. 每一步指针状态
- 起始:
p
指向V
,输出V
,指针移动。 - 遇到
%
:调用*++p
,跳过%
,获取下一个字符'd'
。 - 解析
d
后输出42
,继续处理后续字符。
示例输出分析
对于上述代码调用:
minprintf("Value: %d, Name: %s, Score: %f\n", 42, "Alice", 95.5);
步骤:
- 输出普通字符:
Value:
。 - 遇到
%d
:*++p
解引用,获取d
。- 提取整数
42
,格式化输出为42
。
- 输出普通字符:
, Name:
。 - 遇到
%s
:*++p
解引用,获取s
。- 提取字符串
"Alice"
,逐字符输出为Alice
。
- 输出普通字符:
, Score:
。 - 遇到
%f
:*++p
解引用,获取f
。- 提取浮点数
95.5
,格式化输出为95.500000
(默认 6 位小数)。
- 输出换行符
\n
。
最终输出:
Value: 42, Name: Alice, Score: 95.500000
总结
*++p
的作用:++p
移动指针到下一字符。*++p
解引用获取当前字符,用于格式说明符处理。
- 代码实现思路:
- 遍历格式化字符串,按字符解析。
- 对于普通字符,直接输出。
- 遇到
%
时,通过*++p
获取说明符,并提取参数处理。
- 关键点:
va_list
的使用使得minprintf
能够处理可变参数。*++p
高效实现格式说明符解析,是简化实现的核心。
这段代码简单直观,体现了 C 语言实现格式化输出的核心思想,是理解 printf
工作原理的重要案例。
后记
2025年1月27日于山东日照。