2011-12-06 18 views
2

在很長一段時間以來,我們一直有這樣的工作很多這樣的記錄系統:檢測在printf函數()調用的參數

#define LOG(LEVEL, FORMAT, ...) my_log_function(LEVEL, __FUNCTION__, \ 
             __LINE__, FORMAT, __VA_ARGS__) 

my_log_function將檢查日誌記錄的級別目前到位,如果可以的話,會做一些漂亮的打印(文件/行,它記錄的日期,時間等)。

現在的問題是,這個宏定義有兩個巨大的缺點:

/使用時,在微距傳輸的參數評估,這意味着大量的性能命中時,你的代碼是擁擠通過LOG()調用。

見這裏的例子:

LOG(INFO, "The parameters: %s %d %d\n", heavyMethod().name(),  
     heavyMethod2().id(), work_done_in_this_function()); 

即使「INFO」日誌記錄級別被禁用,所有參數都將進入該功能前進行評估。
如果您登錄函數調用,你會看到這樣的情況:

  • 調用heavyMethod()
  • 調用name()
  • 調用heavyMethod2()
  • 調用id()
  • 調用work_done_in_this_function()
  • (最後)致電my_log_function()

當你有1000個LOG()調用時,這很糟糕。

解決方法很簡單:拿出的my_log_function,檢查水平的代碼並修改這樣的LOG()的定義:

#define LOG(LVL, FMT, ...) do{ if(level_enabled(LVL))  \ 
            {        \ 
            my_log_function(LVL, ...); \ 
            }        \ 
           }while(0) 

這可以確保當日志級別是不足夠的,參數沒有評估(因爲它們在括號內)。

/正如你在我的例子中看到的那樣,被調用的最後一個函數正在做某種工作,如果沒有調用LOG()函數就不會完成這些工作。
這在我們的代碼中發生了很多(我知道,這個SUCKS HARD,人們已經失去了手指)。

隨着我在點 /中所作的增強,我們現在必須檢查每個LOG()調用,以查看是否已完成一些未做的工作,現在我們中止了調用。

這是你們輸入的地方:你知道一個簡單的方法來檢查一個函數的參數是否實際上正在修改某些東西嗎?

該項目是在C++中,大多數「不會修改任何東西」的函數被標記爲const。

注意它包括像一些技巧:LOG(INFO, "Number of items: %d\n", _item_number++);,其中_item_number是一個對象的類的成員(因此如果INFO級未激活:-(沒有得到遞增)

TL; DR: 。永遠,永遠做工作的printf()始終做到這一點,事前:

// BAD 
printf("Number: %d\n",++i); 

// GOOD 
i++; 
printf("Number: %d\n", i); 
+0

'#define'宏是[evil](http://www.parashift.com/c++-faq-lite/inline-functions.html#faq-9.5) –

+0

@Als:高亮顯示它:) – Gui13

+0

printf( 「Number:%d \ n」,++ i); –

回答

2

基本上,你要檢查純函數(即,沒有任何副作用的)一個簡單的方法來檢查,這是。檢查它是否沒有寫入全局內存。

GCC支持多種強制執行方式。首先,存在const屬性,該屬性在應用於函數時會導致其無法從全局內存(僅限自己的堆棧)讀取或寫入數據。問題是,這可能會對你想要的有點限制。

另外還有pure屬性,它基本上是相同的,但允許從全局內存訪問,而不是它,這也應該執行你想要什麼。

通過將方法聲明放入__attribute__(pure)(或__attribute__(const))來應用其中的每一個。可悲的是,我不認爲有一種強制執行這個的方法,每個調用,儘管可能有一種使用函數指針的方法。我會更新,如果我找到一個。

編號:http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html

編輯:由於上市here,有可能將其應用到一個函數指針雖然我不認爲有辦法做到這一點不嵌入一個函數指針到每個方法調用你的宏(它需要知道每個函數的參數佈局),或者聲明你的所有函數都是純的。編輯2:是的,這也不會在您的參數列表中看到像i++這樣的東西。這些將不得不使用我認爲的一些正則表達式來完成。

+0

我選擇了你的答案,因爲它在上下文中提供了信息,儘管它沒有解決它。在我這邊,我通過查看每個和所有對LOG()的調用...來解決這個問題,這個調用總共達到了45K或者什麼的。這不是一種快樂,但並不難(1h)。 – Gui13

+0

是的,我認爲唯一的出路將是一個解析器的地獄,或手動做:( – slugonamission