C语言中的范围保护
我想在C中使用scope guard来进行分析 我想知道我花了多少时间在一个函数上。以下是我的工作:C语言中的范围保护,c,scope,guard,C,Scope,Guard,我想在C中使用scope guard来进行分析 我想知道我花了多少时间在一个函数上。以下是我的工作: int function() { tic(); ... do stuff ... if (something) { toc(); return 0; } toc(); return 1; } 每次退出函数时,我都需要放置一个toc语句。我想这样做,而不必复制粘贴到任何地方。有没有一种通用的方法可以做到这一点,使用宏或其他什么? 另外,我不想改
int function() {
tic();
... do stuff ...
if (something)
{
toc();
return 0;
}
toc();
return 1;
}
每次退出函数时,我都需要放置一个toc语句。我想这样做,而不必复制粘贴到任何地方。有没有一种通用的方法可以做到这一点,使用宏或其他什么?
另外,我不想改变调用函数的方式,因为有许多函数我必须分析
谢谢您可以定义如下宏:
#define TOC_RETURN(x) \
do { \
toc(); \
return x; \
} while(0)
它应该在你放的任何地方都能用。然后您可以自动替换
return*
使用TOC\u RETURN(*)
Hmm,可以将函数调用包装到宏中(真的是宏族)?下面是一个不接受参数并返回Retval的函数:
// define the wrapper for name
#define DEFTIMECALL0(Retval,name) \
Retval timed##name() \
{ \
Retval ret;
tic(); \
ret = name(); \
toc(); \
return ret; \
}
对于所进行的每一次函数调用,都需要宏,返回的版本为Retval和void
Edit定义包装函数可能没有意义,最好只使用一系列宏(同样,对于每个arity和返回类型/void版本),将函数调用直接包装在调用站点的tic/toc中
不要害怕插入探查器,它基本上是为您完成这项工作的。我不建议为此使用宏。您只需偶尔对代码进行一次评测,而将“return”替换为某些特殊的宏(仅用于此目的)会降低代码的可读性 这样做不是更好吗
tic();
call_function();
toc();
这将自动处理函数中的“所有退出点”
另外,为什么不使用剖析器?真正的剖析器不需要您修改代码,只需要在启用剖析的情况下编译代码。为什么不使用实际的剖析工具,比如?您可以通过宏“重新定义”返回:(请参阅免责声明)
#包括
void tic(){printf(“tic\n”);}
void toc(){printf(“toc\n”;}
#定义return toc();return
int foo(){
tic();
返回0;
}
#未定义返回
int main(){
foo();
返回0;
}
免责声明:这可以被认为是丑陋和骇人的,因为:
- 除非使用return;-语句,否则它对void函数不起作用
- 它可能不是便携式/标准的,即使它可以在MSVC8上工作
- 人们不应该定义关键词
static inline int real_function() {
// previous contents of function(), with no tic or toc
}
int function() {
tic();
int r = real_function();
toc();
return r;
}
正如其他人所说:使用分析器,从长远来看,它将为您节省大量的精力。正如他们所说:如果您的平台有分析器
如果没有,那么最简单的可能是说(作为编码规则)函数必须只有一个退出点,并且该退出点必须通过您的宏。然后您可以在进入和退出时手动为所有函数插入代码。具有多个返回的旧函数可以如上所述进行包装
此外,请记住,当您执行类似操作时,编译器可能会把您搞砸。您可以编写以下代码:
tic();
do_something();
int i = something_else();
toc();
return i;
如果编译器确定其他内容没有副作用,那么即使其他内容需要花费大量时间,它也可能会将代码转换为以下内容:
tic();
do_something();
toc();
return something_else();
您的配置文件数据将低估在函数中花费的时间。另一个原因是有一个真正的配置文件器非常好-它可以与编译器合作。我参加聚会已经很晚了,但是在C中有另一种使用GCC扩展属性进行范围保护的方法。cleanup
属性附加了一个函数n到变量超出作用域时运行的变量声明。最初用于对动态分配的类型执行内存释放,也可以将其用作作用域保护
void cleanup_toc(int*忽略uu属性uu((u未使用u)){toc();}
int函数(void){
tic();
int atexit uuuu属性uuu((uuu cleanup uu(cleanup _toc)))=0;
//…做事。。。
如果(某物){
返回0;
}
返回1;
}
此解决方案不使用宏,但您当然可以将其包装到宏中。例如:
#定义串联_IMPL(x,y)x##y
#定义连接(x,y)连接(x,y)
#定义ATEXIT(f)int连接(ATEXIT,_线__)_属性__((_清理__(f)))=0
int函数(void){
ATEXIT(cleanup1);//它们是按相反的顺序执行的,即。
ATEXIT(cleanup2);//cleanup2将在cleanup1之前运行。
}
更改了措辞以避免任何潜在的混淆。:)这是不可组合的。这是我一整天看到的最漂亮的C滥用!
tic();
do_something();
toc();
return something_else();