在我正在进行的项目中,我们同意仅使用返回错误代码(无例外)的函数来处理错误。
为了不污染"我的代码与调试消息我正在研究基于仪器的解决方案(灵感来自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 :(得分: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就会增加很少的开销。