2016-07-03 91 views
2

在我正在開發的項目中,我們同意只使用返回錯誤代碼(無例外)的函數來處理錯誤。通過參數值檢測

爲了不用調試消息「污染」我的代碼,我正在研究基於儀器的解決方案(受this post的啓發)。

代替使用整數作爲錯誤代碼的,我在一個類封裝它爲:

// File rc.h 
class rc 
{ 
public: 
    rc(int) __attribute__((no_instrument_function)); 
    rc& operator=(rc); 
private: 
    int value; 
}; 

接着定義這些運營商和儀表功能:

// File rc.cc 
#include <stdio.h> 
#include <time.h> 
#include "rc.h" 

static FILE *fp_trace; 
static int isError;  

extern "C" 
{ 

    void __attribute__ ((constructor)) trace_begin (void) 
    { 
     fp_trace = fopen("trace.out", "w"); 
     isError = 0; 
    } 

    void __attribute__ ((destructor)) trace_end (void) 
    { 
     if(fp_trace != NULL) { 
     fclose(fp_trace); 
     } 
    } 

    void __cyg_profile_func_enter (void *func, void *caller) __attribute__((no_instrument_function)); 
    void __cyg_profile_func_exit (void *func, void *caller) __attribute__((no_instrument_function)); 

    void __cyg_profile_func_enter (void *func, void *caller) 
    { 
    } 

    void __cyg_profile_func_exit (void *func, void *caller) 
    { 
    if ((fp_trace != NULL) && (isError == 1)) { 
     fprintf(fp_trace, "x %p %p %lu\n", func, caller, time(NULL)); 
     isError = 0; 
    } 
    } 
} 

rc::rc(int valueIn) : 
    value(valueIn) 
{ 
} 

rc& rc::operator=(rc rcIn) 
{ 
    value = rcIn.value; 
    if (value != 0) 
    { 
     isError = 1; 
     fprintf(fp_trace, "%d\n", value); 
    } 
    return *this; 
} 

然而,在爲了不打印太多的東西,我不想記錄返回代碼爲0的函數調用,因此標記爲isError

這可以用下面的例子中:

#include <cstdlib> 
#include <ctime> 
#include "rc.h" 

rc bar(void) 
{ 
    rc result(std::rand() % 3); 
    return result; 
} 

int main(void) 
{ 
    std::srand (std::time(NULL)); 
    rc returnCode(0); 
    for (int i=0; i<10; ++i) 
    { 
    returnCode = bar(); 
    } 
    return 0; 
} 

編譯和

g++ -finstrument-functions -g -c -o rc.o rc.cc 
g++ -g -c -o test.o test.cc 
g++ test.o rc.o -o a.out 
./a.out 

閱讀給定in the previously mentioned post腳本輸出將導致類似運行:

Error code 2 
rc::operator=(rc) at 2016-07-03T18:32:09+0200, called from main (test.cc:32) 

這幾乎是我所希望的。但與一個解決方案相比,我只需在rc foo(void)中添加一個測試來測試輸出是否爲非零,然後記錄錯誤,那麼在發生錯誤的情況下,僅會增加開銷(加上檢查的開銷)希望不會太頻繁),我會添加開銷,由於儀器(加上可能的開銷,由於rc包裝,但我很好)在每次調用...

有沒有解決方案,我couldn沒有想過,在參數爲零的情況下,這不會影響operator=?由於rc::value僅在運行時才爲人所知,因此我不認爲具有參數值的模板將專用於value=0,並且不適用於該情況。會嗎?

還有一個額外的約束:重要的是instrumentation函數是賦值運算符,因爲我想知道調用者,因此我無法添加一些額外的代理級別。


在這最後一點編輯,我想過讓賦值運算符在線的(而不是儀表)和調用的返回碼不爲零的情況下的檢測功能但不能工作爲finstrument-function doc page指出:

此工具也適用於在其他函數中內聯擴展的函數。概要分析調用將指示概念上在何處輸入和退出內聯函數。

因此它沒有指向真正的來電者。

+0

你知道,除非你從頭開始編寫所有的代碼,並且從不使用任何C++庫,否則在程序中你可能會遇到異常。 –

+0

是的,我知道這一點。但我們正在重寫很多東西...... – Vser

+0

一個好的提示是使用負數作爲錯誤代碼,結果的正值(包括0)。這就是Linux系統調用的功能。 –

回答

0

解決方案不是依靠儀器,而是依靠儀器使用的__builtin_return_address(unsigned int)功能。

您可以使用此函數獲取調用者的返回指針:

rc& rc::operator=(rc rcIn) 
{ 
    value = rcIn.value; 
    if (value != 0) 
    { 
     fprintf(fp_trace, "%d %p\n", value, __builtin_return_address(1)); 
    } 
    return *this; 
} 

這樣,你並不需要依靠儀器獲得致電者的地址,並在使用加真小的開銷只是一個整數。