但是通常我們需要在記錄日誌的時候記錄更多的資訊,比如說執行時間等,所以我們不能使用一條簡單的printf來完成該操作,另外,為防止日誌資訊以外丟失,我們最好是在每次printf後立即呼叫fflush。所以我們通常會使用下面的方法來完成日誌記錄操作:
void
__cdecl log0 (
const
char
* _format, ...)
從該**可以看出,我們必須事先定義好乙個我們認為足夠大的快取已儲存所有可能的資料,這就是使用該方法帶來的inflexibility,究竟多大才算足夠大啊?10240?102400?甚至1024000?恐怕你的棧也沒這麼大吧!即使你在堆中分配儲存空間也一樣!
接下來我就介紹一種不用預先分配快取並且能夠接受並輸出任意長度的資訊至日至檔案中(當然,只要不超過你的系統允許的大小),試想,只要我們在log0中完成了我們想做的任何事(比如輸出日誌字首資訊等),並且如果能夠將呼叫者傳遞給log0的引數「原封不動」的傳遞給printf的話,即將所有的可變引數按照printf所要求的格式傳遞給它,由它來完成剩下的操作。這是不是就克服了使用預先分配快取的問題呢?沒錯,接下來所要解決的就是怎樣將這些可變引數「傳遞」給printf。
由於在log0內部,我們不知道呼叫者究竟傳遞了多少個引數進來,所以我們不能按照通常所用的按照引數名的方式將引數傳遞給printf。但是,先別急,看看log0的函式宣告,他是不是和printf的宣告完全一致呢(事實上只要是log0中的引數和printf中的部分一致也可,如voidlog1(char* filename, int len, char* _format, ...)也可。)?
也就是說擁有相同宣告的函式,在被呼叫時,他們所擁有的引數棧(即stackframe)的結構是一樣的。所以,只要我們能夠從乙個函式a「突然」跳轉到另外乙個函式b中,那麼b所擁有的引數棧和a將是同乙份資料,即他們「共享」了同乙份引數棧資料。需要注意的是,這裡的跳轉不能使用通常的函式掉用來實現,因為函式被呼叫時,編譯器會在背後做很多事情,如給我們設定新的esp指標等等,因此這樣勢必不能達到共享引數棧資料的目的。為了不讓編譯器在函式呼叫時在背後做任何事情,我們需要使用乙個naked函式,在這樣的函式中我們就可以自己利用棧資源,自己控制所有一切。有了這樣的函式後,就可以很輕鬆,而且很高效的達到我們的目的了。
void
mkprefix ()
__declspec (naked)
void
__cdecl
xprintf (
const
char
* _format, ...) }
**中在1和2處分別對esp減4後又加4,所以這兩處的**完全可以忽略,在這裡加上是為了更好的理解函式呼叫的機制(即在函式呼叫後需要修正esp,即所謂的stackclean-up)。你可以將mkprefix 作的足夠複雜已記錄更多的資訊,甚至我們可以通過log0將引數傳遞到mkprefix 中,向log1那樣。不過這樣處理起來就稍複雜點,為簡單起見,就不再講述這種方法了。
當然,這只是這種所謂的「棧共享」技術的乙個應用而已了,掌握了這種技術後,我想你肯定會把它應用到其他更適合的地方。
其實,在vc8中,由於提供了可變引數的巨集,所以我們可以通過下面一條簡單的呼叫來完成日至記錄操作,而且資訊還比較完全:
#define
trace(fmt, ...) printf ("%s (%s:%d) - "##fmt, mkprefix(), __file__, __line__, __va_args__)
trace (
"this is a debug information, a = %d, b = %s.",
234,
"***xx");
用printf做彩色日誌記錄 及巨集定義printf
c程式設計在linux上 用printf做彩色日誌記錄 寫了乙個簡單的程式,但是考慮到有一些資訊是需要列印在控制台上的,就像在windows上啟動apache tomcat時控制台顯示的資訊一樣。琢磨一會兒之後,對printf進行了封裝,支援控制台列印日誌,支援輸出到檔案裡。不過控制台都是固定顏色的...
C 使用TraceSource記錄程式日誌
tracesource類的前身是trace與debug。在專案的實際使用過程中,一般通過以下步驟使用 定義配置檔案.config 配置tracesource的源 控制級別 等 定義tracesource物件,可以簡單封裝 using system using system.collections.g...
C 使用Trace記錄程式日誌
在程式開發中,我們通常需要記錄程式執行的狀態,在程式部署後,發生的異常可以記錄在日誌中,便於發現程式潛在的問題。在.net平台,有很多優秀的日誌類庫,例如log4net。如果程式很小,我們可以自己通過c 的trace類來實現乙個基本的日誌記錄功能。下面直接看 public class tracehe...