• <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

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

            “傳遞/轉(zhuǎn)發(fā)”可變參數(shù)并通過printf記錄程序日志,徹底告別vsnprintf!:)

            通常我們需要在程序中輸出部分日志信息,并把它記錄到文件中。在這種情況下,使用printf可以為我們帶了很大方便。因為printf卻省情況下是向stdout即控制臺屏幕輸出信息,在GUI程序中,我們看不到printf的輸出結(jié)果,但是我們可以將該輸出重定向到指定的文件中。即使用freopen(“c:\\yourlog.log”, “a+”,stdout)或通過yourapp.exe > c:\yourlog.log完成輸出重定向操作。

            但是通常我們需要在記錄日志的時候記錄更多的信息,比如說運行時間等,所以我們不能使用一條簡單的printf來完成該操作,另外,為防止日志信息以外丟失,我們最好是在每次printf后立即調(diào)用fflush。所以我們通常會使用下面的方法來完成日志記錄操作:

            void __cdecl log0 (const char* _Format, ...)
            {
               
            char buff[10240], tm[80];
                va_list vl;
                va_start (vl, _Format);

                _strtime (tm);
                vsnprintf (buff, 10240, _Format, vl);
                printf ("%s - %s", tm, buff);
                fflush (stdout);

                va_end (vl);
            }

            從該代碼可以看出,我們必須事先定義好一個我們認為足夠大的緩存已存儲所有可能的數(shù)據(jù),這就是使用該方法帶來的inflexibility,究竟多大才算足夠大啊?10240102400?甚至1024000?恐怕你的棧也沒這么大吧!即使你在堆中分配存儲空間也一樣!
            接下來我就介紹一種不用預先分配緩存并且能夠接受并輸出任意長度的信息至日至文件中(當然,只要不超過你的系統(tǒng)允許的大小),試想,只要我們在log0中完成了我們想做的任何事(比如輸出日志前綴信息等),并且如果能夠?qū)⒄{(diào)用者傳遞給log0的參數(shù)原封不動的傳遞給printf的話,即將所有的可變參數(shù)按照printf所要求的格式傳遞給它,由它來完成剩下的操作。這是不是就克服了使用預先分配緩存的問題呢?沒錯,接下來所要解決的就是怎樣將這些可變參數(shù)傳遞printf

            由于在log0內(nèi)部,我們不知道調(diào)用者究竟傳遞了多少個參數(shù)進來,所以我們不能按照通常所用的按照參數(shù)名的方式將參數(shù)傳遞給printf。但是,先別急,看看log0的函數(shù)聲明,他是不是和printf的聲明完全一致呢(事實上只要是log0中的參數(shù)和printf中的部分一致也可,如void log1(char* filename, int len, char* _Format, ...)也可。)?

            也就是說擁有相同聲明的函數(shù),在被調(diào)用時,他們所擁有的參數(shù)棧(即Stack Frame)的結(jié)構(gòu)是一樣的。所以,只要我們能夠從一個函數(shù)A“突然跳轉(zhuǎn)到另外一個函數(shù)B中,那么B所擁有的參數(shù)棧和A將是同一份數(shù)據(jù),即他們共享了同一份參數(shù)棧數(shù)據(jù)。需要注意的是,這里的跳轉(zhuǎn)不能使用通常的函數(shù)掉用來實現(xiàn),因為函數(shù)被調(diào)用時,編譯器會在背后做很多事情,如給我們設(shè)置新的ESP指針等等,因此這樣勢必不能達到共享參數(shù)棧數(shù)據(jù)的目的。為了不讓編譯器在函數(shù)調(diào)用時在背后做任何事情,我們需要使用一個naked函數(shù),在這樣的函數(shù)中我們就可以自己利用棧資源,自己控制所有一切。有了這樣的函數(shù)后,就可以很輕松,而且很高效的達到我們的目的了。

            void mkprefix ()
            {  
            char buff[80];
                _strtime (buff);
                printf ("%s - ", buff);
            }


            __declspec (naked)
            void __cdecl
            xprintf (
            const char* _Format, ...)
            {
                __asm
                {   call    dword ptr [mkprefix]

                    pop     ebx
            /* 將函數(shù)返回地址保存到EBX */
                    call    dword ptr [printf]
                    sub     esp, 4    /* 1 */


                   
            /* 調(diào)用fflush將數(shù)據(jù)立即保存到文件中 */
                    call    dword ptr [__iob_func]
                    add     eax, 0x20

                    push    eax
                    call    dword ptr [fflush]
                    add     esp, 4  /* 2 */


                    mov     dword ptr [esp], ebx
            /* 恢復函數(shù)返回地址 */
                    ret
                }

            }

            代碼中在12處分別對ESP4后又加4,所以這兩處的代碼完全可以忽略,在這里加上是為了更好的理解函數(shù)調(diào)用的機制(即在函數(shù)調(diào)用后需要修正ESP,即所謂的Stack clean-up)。你可以將mkprefix 作的足夠復雜已記錄更多的信息,甚至我們可以通過log0將參數(shù)傳遞到mkprefix 中,向log1那樣。不過這樣處理起來就稍復雜點,為簡單起見,就不再講述這種方法了。

            當然,這只是這種所謂的棧共享技術(shù)的一個應用而已了,掌握了這種技術(shù)后,我想你肯定會把它應用到其他更適合的地方。

            其實,在VC8中,由于提供了可變參數(shù)的宏,所以我們可以通過下面一條簡單的調(diào)用來完成日至記錄操作,而且信息還比較完全:

            #define TRACE(fmt, ...) printf ("%s (%s:%d) - "##fmt, mkprefix(), __FILE__, __LINE__, __VA_ARGS__)

            TRACE ("This is a debug information, a = %d, b = %s. ", 234, "xxxxx");

             

            posted on 2009-08-12 13:01 肥仔 閱讀(833) 評論(0)  編輯 收藏 引用 所屬分類: C++ 基礎(chǔ)

            99国产欧美久久久精品蜜芽| 久久国产高清一区二区三区| 精品久久久久久国产潘金莲| 国产一级持黄大片99久久| 91精品国产综合久久四虎久久无码一级 | 99999久久久久久亚洲| 国产—久久香蕉国产线看观看| 久久久久亚洲AV成人网人人网站 | 久久精品无码一区二区无码| 国产成人无码精品久久久免费| 久久综合亚洲色一区二区三区| 91久久精品国产成人久久| 亚洲乱码精品久久久久.. | 久久久久国色AV免费看图片| 欧美亚洲色综久久精品国产| 久久久久国产日韩精品网站| 久久国产高潮流白浆免费观看| 久久久中文字幕日本| 91精品国产色综合久久| 伊人久久大香线蕉精品不卡| 狠狠人妻久久久久久综合| 精品久久久久久| 久久国产热精品波多野结衣AV| 亚洲国产小视频精品久久久三级| 日本精品久久久久中文字幕 | 久久99久久成人免费播放| 国内精品伊人久久久久av一坑 | 日日狠狠久久偷偷色综合免费| 久久久久久免费一区二区三区| 久久综合九色综合网站| 国产亚洲精久久久久久无码77777 国产亚洲精品久久久久秋霞 | 国内精品久久久久影院一蜜桃| 国产精品久久久久免费a∨| 欧美亚洲另类久久综合婷婷| 久久无码人妻精品一区二区三区| 精品久久人人爽天天玩人人妻 | 久久精品中文闷骚内射| 久久国产精品成人片免费| 久久精品国产亚洲欧美| 国产精品九九久久免费视频 | 97精品依人久久久大香线蕉97 |