</pre>printf函數運行機制</p><p><span style="font-size:18px">例如:printf("hello,world\n");</span></p><p><span style="font-size:18px">當前printf函數只有一個參數,可以知道的是printf函數可以有很多不固定數量的參數;但是對於printf函數來說,它執行的是一個輸出打印,一個只讀的操作,不管參數的多少,只要參數大於1個,該函數都會按照一定的規則進行參數的輸出;但是有着一個規定是,printf函數的第一個參數必須是一個字符串地址;所有的打印輸出都是按照這樣的一個字符串進行格式化輸出的;對於當前的hello,world這個程序,調用了這個程序,printf開始將字符串hello,world的首地址進行壓棧;在參數全部壓棧完成之後,將會一個參數一個參數的彈出;</span></p><p><span style="font-size:18px">int i = 10,j = 20;</span></p><p><span style="font-size:18px">printf("The i:%d,j:%d\n",i,j);</span></p><p><span style="font-size:18px">從printf函數的參數進行討論;該函數有三個參數,從j開始進行壓棧,然後是i,最後是字符串首地址;當函數壓棧完成之後,printf函數將會從棧中取出數據,首先彈出的是字符串首地址,"The i:%d,j:%d\n",當遇到了格式佔位符時,將會自動從棧中依次取出數據,進行格式替換;</span></p><p><span style="font-size:18px"></span><pre name="code" class="cpp">int printf(const char * __restrict format, ...)
{
va_list arg;
int rv;
va_start(arg, format);
rv = vfprintf(stdout, format, arg);
va_end(arg);
return rv;
}
Printf函數使用了變參結構(va_list),可以參考其他資料關於講解va_list;va_start中fomart用來表示第一個參數的首地址用來標示參數參數地址起始地址,使用將之後的參數存到va_list結構體中;可以用va_arg(arg, int)接口來獲取參數值,獲取完成之後,arg自動指向下一個參數類型;通過掃描格式化串format,遇到%d,%s將對應的值給打印出來;
示例:
void foo(char *fmt, ...)
{
va_list ap;
int d;
char c, *s;
va_start(ap, fmt);
while (*fmt)
{
if((*fmt++) != '%')
{
continue;
}
switch (*fmt)
{
case 's': /* string */
s = va_arg(ap, char *);
printf("string %s\n", s);
break;
case 'd': /* int */
d = va_arg(ap, int);
printf("int %d\n", d);
break;
case 'c': /* char */
/* need a cast here since va_arg only
takes fully promoted types */
c = (char) va_arg(ap, int);
printf("char %c\n", c);
break;
}
}
va_end(ap);
}