printf的實現原理


printf的聲明
    int _cdecl printf(const char* format, …);
    _cdecl是C和C++程序的缺省調用方式

_CDEDL調用約定:
    1.參數從右到左依次入棧
    2.調用者負責清理堆棧
    3.參數的數量類型不會導致編譯階段的錯誤


對於x86而言,棧向下生長,函數參數從右向左入棧,因此從第一個固定參數(format)地址向前(向上)移動就可得到其他變參的地址。

va_list相關宏(VC++中stdarg.h里x86平台的宏定義)

typedef char *  va_list;
//_INTSIZEOF(n)宏:將sizeof(n)按sizeof(int)對齊。
#define _INTSIZEOF(n)   ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )

//取format參數之后的第一個變參地址,4字節對齊
#define va_start(va_list  ap, format) ( ap = (va_list)&format+ _INTSIZEOF(format) )

//對type類型數據,先取到其四字節對齊地址,再取其值
#define va_arg(va_list  ap,type)  
              ( *(type*)((ap += _INTSIZEOF(type)) -_INTSIZEOF(type)) )

#define va_end(va_list  ap)  ( ap = (va_list)0 )


如何得到參數個數?
其實printf並不知道參數個數,它只是逐個解析format字符串。對於特定類型%,使用va_arg去取相應參數的值,直到遍歷字符串結束。類似於如下代碼:
    #include <stdio.h>
    #include <stdarg.h>
    void myprintf(const char *format, ...)
    {
                va_list ap;
                char ch;
                va_start(ap, format);
                while(ch = *format++)
                {
                        switch(c)
                        {
                                    case 'c':
                                        {
                                                char ch1 = va_arg(ap, char);
                                              putchar(ch1);
                                               break;
                                        }
                                  


如下調用會打印什么內容?
printf("%x");


----------------

背景知識:

函數調用棧幀結構:



比如Z調用A,Z的棧幀:
1.自右向左(約定)壓入參數
2.Z中返回地址。即從A返回后Z中下一條指令地址
3.調用者的EBP。由編譯器插入指令實現:
"pushl %ebp"
"movl %esp, %ebp"//esp為棧指針
因而形成一個鏈表。依此可得到調用者的棧頂位置(對於A的EBP,得到Z的EBP地址為0x000f)。
4.局部變量。



對於兩個正整數 x, n 總存在整數 q, r 使得
x = nq + r, 其中  0<= r <n                  //最小非負剩余
q, r 是唯一確定的。q = [x/n], r = x - n[x/n]. 這個是帶余除法的一個簡單形式。在 c 語言中, q, r 容易計算出來: q = x/n, r = x % n.
所謂把 x 按 n 對齊指的是:若 r=0, 取 qn, 若 r>0, 取 (q+1)n. 這也相當於把 x 表示為:
x = nq + r', 其中 -n < r' <=0                //最大非正剩余
nq 是我們所求。關鍵是如何用 c 語言計算它。由於我們能處理標准的帶余除法,所以可以把這個式子轉換成一個標准的帶余除法,然后加以處理:
x+n = qn + (n+r'),其中 0<n+r'<=n            //最大正剩余
x+n-1 = qn + (n+r'-1), 其中 0<= n+r'-1 <n    //最小非負剩余
所以 qn = [(x+n-1)/n]n. 用 c 語言計算就是:
((x+n-1)/n)*n
若 n 是 2 的方冪, 比如 2^m,則除為右移 m 位,乘為左移 m 位。所以把 x+n-1 的最低 m 個二進制位清 0就可以了。得到:
(x+n-1) & (~(n-1))


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM