• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            woaidongmao

            文章均收錄自他人博客,但不喜標(biāo)題前加-[轉(zhuǎn)貼],因其丑陋,見諒!~
            隨筆 - 1469, 文章 - 0, 評論 - 661, 引用 - 0
            數(shù)據(jù)加載中……

            C語言變參函數(shù)解析

            1 函數(shù)聲明
               首先,要實現(xiàn)類似printf()的變參函數(shù),函數(shù)的最后一個參數(shù)要用 ... 表示,如
                 int log(char * arg1, ...)
            這樣編譯器才能知道這個函數(shù)是變參函數(shù)。這個參數(shù)與變參函數(shù)的內(nèi)部實現(xiàn)完全沒有關(guān)系,只是讓編譯器在編譯調(diào)用此類函數(shù)的語句時不計較參數(shù)多少老老實實地把全部參數(shù)壓棧而不報錯,當(dāng)然...之前至少要有一個普通的參數(shù),這是由實現(xiàn)手段限制的。


            2 函數(shù)實現(xiàn)
               C語言通過幾個宏實現(xiàn)變參的尋址。下面是linux2.18內(nèi)核源碼里這幾個宏的定義,相信符合C89,C99標(biāo)準(zhǔn)的C語言基本都是這樣定義的。
               typedef char *va_list;
            /*
               Storage alignment properties -- 堆棧按機(jī)器字對齊
            */
            #define _AUPBND            (sizeof (acpi_native_uint) - 1)
            #define _ADNBND            (sizeof (acpi_native_uint) - 1)
            /*
               Variable argument list macro definitions -- 變參函數(shù)內(nèi)部實現(xiàn)需要用到的宏
            */
            #define _bnd(X, bnd)          (((sizeof (X)) + (bnd)) & (~(bnd)))
            #define va_arg(ap, T)        (*(T *)(((ap) += (_bnd (T, _AUPBND))) - (_bnd (T,_ADNBND))))
            #define va_end(ap)          (void) 0
            #define va_start(ap, A)        (void) ((ap) = (((char *) &(A)) + (_bnd (A,_AUPBND))))
               下面以x86 32位機(jī)為例分析這幾個宏的用途
               要理解這幾個宏需要對C語言如何傳遞參數(shù)有一定了解。與PASCAL相反,與stdcall 相同,C語言傳遞參數(shù)時是用push指令從右到左將參數(shù)逐個壓棧,因此C語言里通過棧指針來訪問參數(shù)。雖然X86的push一次可以壓2,4或8個字節(jié)入棧,C語言在壓參數(shù)入棧時仍然是機(jī)器字的size為最小單位的,也就是說參數(shù)的地址都是字對齊的,這就是_bnd(X,bnd)存在的原因。另外補(bǔ)充一點常識,不管是匯編還是C,編譯出的X86函數(shù)一般在進(jìn)入函數(shù)體后立即執(zhí)行
               push ebp
               mov ebp, esp
               這兩條指令。首先把ebp入棧,然后將當(dāng)前棧指針賦給ebp,以后訪問棧里的參數(shù)都使用ebp作為基指針。
               一一解釋這幾個宏的作用。
               _bnd(X,bnd) ,計算類型為X的參數(shù)在棧中占據(jù)的字節(jié)數(shù),當(dāng)然是字對齊后的字節(jié)數(shù)了。acpi_native_unit是一個機(jī)器字,32位機(jī)的定義是:typedef u32 acpi_native_uint;
               顯然,_AUPBND ,_ADNBND 的值是 4-1 == 3 == 0x00000003 ,按位取反( ~(bnd))就是0xfffffffc 。
            因此,_bnd(X,bnd) 宏在32位機(jī)下就是
               ( (sizeof(X) + 3)&0xfffffffc )
            很明顯,其作用是--倘若sizeof(X)不是4的整數(shù)倍,去余加4。
               _bnd(sizeof(char),3) == 4
               _bnd(sizeof(struct size7struct),3) == 8
               va_start(ap,A) ,初始化參數(shù)指針ap,將函數(shù)參數(shù)A右邊第一個參數(shù)的地址賦給ap。 A必須是一個參數(shù)的指針,所以此種類型函數(shù)至少要有一個普通的參數(shù)啊。像下面的例子函數(shù),就是將第二個參數(shù)的指針賦給ap。
               va_arg(ap,T) ,獲得ap指向參數(shù)的值,并使ap指向下一個參數(shù),T用來指明當(dāng)前參數(shù)類型。
               注意((ap) += (_bnd (T, _AUPBND))) 是被一對括號括起來的,然后才減去(_bnd (T, _ADNBND),
            而_AUPBND和_ADNBND是相等的。所以取得的值是ap當(dāng)前指向的參數(shù)值,但是先給ap加了當(dāng)前參數(shù)在字對齊后所占的字節(jié)數(shù),使其指向了下一個參數(shù)。
            va_end(ap), 作用是美觀。


            3 總結(jié)
            先用一個 ... 參數(shù)聲明函數(shù)是變參函數(shù),接下來在函數(shù)內(nèi)部以va_start(ap,A)宏初始化參數(shù)指針,然后就可以用va_arg(ap,類型)從左到右逐個獲取參數(shù)值了
            分析到此處算是一清二白了,下面給一個例子
            int log(char * fmt,...)
            {
            va_list ap;
            int d;
            char c, *p, *s;
            va_start(ap, fmt);
            while (*fmt)
               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 */
               c = va_arg(ap, char);
               printf("char %c\n", c);
               break;
            }
            va_end(ap);
            }

            posted on 2008-06-11 14:11 肥仔 閱讀(260) 評論(0)  編輯 收藏 引用 所屬分類: C++ 基礎(chǔ)

            国产亚洲色婷婷久久99精品| AAA级久久久精品无码片| 要久久爱在线免费观看| 新狼窝色AV性久久久久久| 久久97精品久久久久久久不卡| 久久人人爽人人精品视频| 精品久久久久久亚洲精品| 久久免费香蕉视频| 成人久久精品一区二区三区| 色综合久久夜色精品国产| 91精品国产91久久久久久青草| 久久精品国产清自在天天线| 伊人热人久久中文字幕| 亚洲va中文字幕无码久久| 久久久久久一区国产精品| 久久久久中文字幕| 人人狠狠综合久久88成人| 中文国产成人精品久久亚洲精品AⅤ无码精品 | 国产69精品久久久久久人妻精品| 免费观看成人久久网免费观看| 尹人香蕉久久99天天拍| 精品久久久久国产免费| 欧美精品一本久久男人的天堂| 久久国产精品一国产精品金尊| 一级做a爰片久久毛片看看| 久久国产成人午夜aⅴ影院| 久久er国产精品免费观看2| 色8久久人人97超碰香蕉987| 久久久久久久精品妇女99| 综合久久给合久久狠狠狠97色| 久久九九免费高清视频| 久久久久国产精品| 久久精品国产91久久麻豆自制| 久久ww精品w免费人成| 蜜臀久久99精品久久久久久小说| 久久这里只有精品首页| 一级女性全黄久久生活片免费 | 91精品国产高清久久久久久国产嫩草| 国内精品久久久久久99| 久久91精品国产91久久麻豆| 狠狠色丁香久久综合婷婷|