●為什麼要用不定參數寫Log API ?
每次在寫 Log 之前就要宣告一個字串,再用 sprintf 或 Format 來處理,實在不方便,還要去控制字串的宣告位置、次數,多次寫Log的位置都有相同的宣告,程式碼也變得難閱讀。
不如直接將 Format 參數帶入 API,再由 Log API 來處理字串,是更好的方法。

●做法說明
// 以下為資料來源與參考資料文章(Copy & Paste)
http://blog.yam.com/csylvia/article/17973254

先講解一下什麼是不定參數,
最知名的例子就是 printf(),
你可以這樣使用

printf( "Hello." );

也可以這樣使用

printf( "Hello %s", szName );
printf( "Hello %s, you have drunk %d cups of coffee", szName, iNumber );

函式中可以只有一條字串,
也可以字串後夾帶許多參數,
這樣的函式的定義當然不可能是這樣:

printf( char* string, char* param1 );
printf( char* string, char* param1, int param2 );
printf( char* string, int param1 );
...

這樣有幾百、幾千種組合啊?!=口=|||b

這就是「不定參數」發揮的地方了。

可以看到 printf 的 prototype:

int printf(const char *format [,argument]...);

那三個點就是表示不定參數(參數的個數、型態不限定)。

用法大家非常清楚,
那假如今天想寫一個接受不定參數的函式要怎麼做?

這就要應用到 va_arg()、va_end()、va_start() 三個 macro 來完成,
根據手邊的《C/C++》內的說明如下:
va_arg():它可以讓函數後面所接的引數不必維持固定的個數。第一次呼叫時,會傳回引數列最前面的第一個引數,接下來每次呼叫會自動傳回下一個引數內容。
va_end():當使用 va_arg() 完成取得所有引數內容後呼叫此 macro,通常是為了執行 return 動作。
va_start():在使用 va_arg() 前必須先呼叫此 macro,如此才能順利找到「不定引數列」的最前面內容。

此外還有幾個相關函式:
vfprintf():將 argument list 的內容輸出到資料流。
vprintf():將 argument list 的值寫到標準輸出(standard output)。
vsprintf():將 argument list 的值輸出到字串緩衝區(string buffer)。

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

/*
NAME:
    WriteLog(LPCTSTR sFormat, ...)
PARAMETER:
    sFormat : 傳入的 Format 字串
    ...     : Format 字串的參數
RETURN:
COMMENT:
*/
void CTekKLine::WriteLog(LPCTSTR sFormat, ...)
{
    va_list     pArgList;
    TCHAR       sBuffer[2048];
    FILE       *pFile;
    CString     sPath;
    CString     sTemp;
    CTime       tNow = CTime::GetCurrentTime();

    // 取出傳入的 Format
    va_start(pArgList, sFormat);
    _vsnwprintf(sBuffer, sizeof(sBuffer) / sizeof(TCHAR), sFormat, pArgList);
    va_end(pArgList);

    // 建立資料夾
    sPath = _T(".\\log");
    CreateDirectory(sPath, NULL);
   
    // 組成路徑
    sTemp.Format(_T("%s\\kline.log"), sPath);
    pFile = _tfopen(sTemp, _T("a+t"));
   
    // 寫入檔案
    sTemp.Format(_T("[%04d%02d%02d %02d:%02d:%02d] %s\n"),
                tNow.GetYear(), tNow.GetMonth(), tNow.GetDay(), tNow.GetHour(), tNow.GetMinute(), tNow.GetSecond(),
                sBuffer);
    _fputts(sTemp, pFile);
   
    fclose(pFile);
}

arrow
arrow
    全站熱搜

    freestyler 發表在 痞客邦 留言(0) 人氣()