[英]Tracing of function calls in C
我正在為用C編寫的自動化系統開發一些模塊,我需要使用硬件執行大量工作。 我沒有看到調試事物而不是跟蹤日志的簡單方法(如傳統方法)。 所以我正在尋找一個記錄函數調用的好習慣。 至少調用和返回值的順序。
它在應用程序中執行的方式非常簡單,並且實際上使用不相關的結構來污染代碼
int function (int param){
if(trace_level & LOG_FCALLS){
writelog("Entering function()");
}
/* something useful */
if(trace_level & LOG_FCALLS){
writelog("Exit from function()=%d", ret);
}
}
我決定使用一個可以完成所有臟工作的宏。 現在看起來像這樣
#define LOG_E(fn) const char *__fname=fn; printf("LOG: Entry to %s\n",__fname)
#define return(ret) printf("LOG: Exit from %s()=%d\n",__fname,ret)
int testFunc(){
LOG_E("testFunc");
/*do useful things */
return(ret);
}
我看到了這段代碼的問題
我正在覆蓋return語句,並且需要一直寫return(ret)
而不是return ret
。 很容易忘記這個問題。
我在我的宏中定義字符串變量。 我知道在C99中存在__func__
宏,但不幸的是,我的編譯器不支持這個宏或任何其他相關的宏。
如何記錄函數參數的值?
我很確定這不是一個新問題,我不是第一個面對它的人。 我也知道AOP的事情,但代碼檢測是我的系統不可接受的解決方案,我沒有發現任何可能與我的編譯器。
所以我正在尋找一個好主意如何以最優雅的方式實現跟蹤。
我的環境:傳統代碼,C,Watcom 10.x,實時操作系統
執行此操作的超級嚴謹,專業的方法是創建一個單獨的調試/測試項目,該項目完全獨立於生產代碼。 它是這樣的:
創建一個.txt日志文件,您可以在其中編寫要記錄的每個函數的完整簽名,例如:
int function (int param) float function2 (void) ...
{
和之前}
之后,它將調試日志代碼插入所需的函數中。 你需要幾個小時的時間來完成這樣的計划。 上面的方法是我自己在關鍵任務軟件上做的,你有安全標准(MISRA,代碼覆蓋等)的要求,說沒有允許在最終產品中執行的代碼。
此方法可確保生產代碼的完整性,並確保測試/調試代碼不會將任何意外錯誤添加到程序中。 它還使生成代碼中的編譯開關等雜亂無章。 並且您將不會在您的項目中保留任何舊的調試代碼而您忘記刪除(否則我總是在我的程序中忘記一些調試代碼片段)。
#if defined(DEBUG_BUILD)
# define START_FUNCTION if(trace_level & LOG_FCALLS){writelog("+++ %s()", __func__)
}
# define END_FUNCTION if(trace_level & LOG_FCALLS){writelog("--- %s()", __func__)
#elif defined (TIMING_BUILD)
# define START_FUNCTION WRITE_TIMED_LOG("+++")
# define END_FUNCTION WRITE_TIMED_LOG("---")
#else
# define START_FUNCTION
# define END_FUNCTION
#endif
int function (int param){
START_FUNCTION;
...
if(error_occurred) {
END_FUNCTION;
return errror_code;
}
...
END_FUNCTION;
return 42;
}
這適用於MS Visual C.對於不同的數據類型(或無),您將需要不同版本的return
宏。
#include <stdio.h>
#define TRACING
#ifdef TRACING
#define LOG_E printf("Func: %s\n", __FUNCTION__);
#define LOG_R printf("Exit: %s\n", __FUNCTION__);
#define LOG_I(ival) printf("Exit: %s %d\n", __FUNCTION__, ival);
#else
#define LOG_E
#define LOG_R
#define LOG_I(ival)
#endif
int main(void){
int retval = 0;
LOG_E
printf("Hello world!\n");
LOG_I(retval)
return retval;
}
輸出:
Func: main
Hello world!
Exit: main 0
您可以自定義編譯器來處理它。 如果要使用GCC進行編譯,可以使用MELT (自定義gcc
編譯器)。
也許您可以自定義openwatcom (或支付一些OpenWatcom專家來做到這一點)......
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.