2016-07-03 5 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, но я в порядке) при каждом вызове ...

Есть ли решение, Не подумал, что это не повлияло бы на operator= в случае, когда аргумент равен нулю? Поскольку rc::value известен только во время выполнения, я не думаю, что шаблон с аргументом имеет значение, которое будет специализировано для value=0 и не будет работать в этом случае. Не так ли?

Существует дополнительное ограничение: важно, чтобы инструментальная функция была оператором присваивания, так как я хочу знать вызывающего, поэтому я не могу добавить дополнительный уровень прокси.


редактировать на этом последнем пункте, я думал о создании встроенный оператор присваивания (а не инструментальными) и вызовите инструментальную функцию в случае код возврата не равен нулю, но это не может работа 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; 
} 

Таким образом, вы не должны полагаться на аппаратуры для получения адреса вызывающего абонента и добавит действительно мало накладных расходов по сравнению с использованием просто int.

 Смежные вопросы

  • Нет связанных вопросов^_^