printf 是 C 语言的一个最基本的内建函数。它是一个可变形参的函数,可以接纳任意数目任意类型的参数。最近项目上有个需求,用户希望自定义可变参数的函数,来实现类似 printf 的功能,方便跨平台移植代码。虽然我也不明白这个需求,但是必须得研究一下 printf 函数的底层实现了,于是边学边记录吧。
printf 的参数保存
在 C/C++ 中,对函数参数的扫描是从右往左的。C/C++ 的函数参数是通过栈的方式来给函数传参数的。
注1:栈是一种 LIFO(last in first out) 数据结构,最后压入的参数最先被取出来。栈是内存中的一块连续空间,从内存的高地址向低地址生长。栈顶的指针始终是被记住的,且在内存中为低地址。压入新的参数后,栈顶指针被更新。
由于 C/C++ 的函数参数通过栈的方式来保存,且参数的保存方式是从右往左,因此下面的调用,最先被压入栈中的是 i3,其次是 i2,i1,最后是格式字符串。
printf("Let's print three number: %d, %d, %d", i1, i2, i3);
注2:C 语言之所以选择从右往左的函数参数入栈方式,就是为了支持可变形参。栈顶的参数最容易得到,格式字符串放在栈顶,可以很便捷的得到控制参数的个数(根据%d,%s等),从而可以知道栈内的函数传参个数。
printf 的实现原理
printf 实现的时候需要用到宏,这些宏定义在了 stdarg.h 中
C 语言在调用的时候,会使用到其