我想在C中使用范围保护来进行分析。
我想知道我在一个功能中花了多少时间。这是我的工作:
int function() {
tic();
... do stuff ...
if (something)
{
toc();
return 0;
}
toc();
return 1;
}
每次退出函数时我都需要放置一个toc语句。我想这样做,而无需到处复制粘贴toc。有没有通用的方法来做到这一点,使用宏或什么? 此外,我不想改变调用函数的方式,因为我需要分析许多函数。
由于
答案 0 :(得分:5)
这不会改变调用函数的方式。但是,如果您希望能够分析每个功能,可能没什么用。
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;
如果编译器确定something_else没有副作用,那么即使something_else花费大量时间,它也可能将代码转换为:
tic();
do_something();
toc();
return something_else();
您的个人资料数据会低估您在函数中花费的时间。有一个真实的探查器是如此之好的另一个原因 - 它可以与编译器合作。
答案 1 :(得分:4)
您可以定义一个宏,如:
#define TOC_RETURN(x) \
do { \
toc(); \
return x; \
} while(0)
哪个应该可以在任何地方使用它。然后,您可以使用return *;
自动替换TOC_RETURN(*)
。
答案 2 :(得分:4)
为什么不使用实际的分析工具,例如gprof?
答案 3 :(得分:2)
您可以通过宏“重新定义”返回:(请参阅免责声明)
#include <stdio.h>
void tic() { printf("tic\n"); }
void toc() { printf("toc\n"; }
#define return toc(); return
int foo() {
tic();
return 0;
}
#undef return
int main() {
foo();
return 0;
}
免责声明:这可以被视为丑陋和黑客,因为:
答案 4 :(得分:1)
我不会为此推荐一个宏。您只需偶尔对代码进行一次分析,并将“return”替换为一些特殊的宏仅仅是为了这个目的,这会使代码的可读性降低。
这样做不是更好吗?
tic();
call_function();
toc();
这会自动处理函数中的“所有退出点”。
P.S。你为什么不使用探查器?
答案 5 :(得分:1)
真正的分析器不需要您修改代码,只需要在启用分析的情况下编译它。
答案 6 :(得分:0)
嗯,也许将函数调用包装在一个宏(宏的系列,真的)中?这是一个不带参数并返回Retval:
的// define the wrapper for name
#define DEFTIMECALL0(Retval,name) \
Retval timed##name() \
{ \
Retval ret;
tic(); \
ret = name(); \
toc(); \
return ret; \
}
你需要为每个函数调用提供宏,并使用Retval和void返回版本。
编辑也许在定义包装器函数时甚至没有意义,更好的是只有一个宏系列(同样,对于每个arity和返回类型/ void版本)包装一个函数直接在调用的tic / toc中调用
不要害怕检测分析器,这基本上是为你做的。
答案 7 :(得分:0)
我很晚才参加聚会,但是还有另一种使用GCC扩展cleanup
属性在C中进行范围保护的方法。 cleanup
属性将函数附加到变量声明,该变量声明在变量超出范围时运行。最初旨在为动态分配的类型执行内存释放,但它也可以被用作作用域保护。
void cleanup_toc(int *ignored __attribute__((__unused__))) { toc(); }
int function(void) {
tic();
int atexit __attribute__((__cleanup__(cleanup_toc))) = 0;
//... do stuff ...
if (something) {
return 0;
}
return 1;
}
此解决方案不使用宏,但是您当然可以将其包装到宏中。例如:
#define CONCATENATE_IMPL(x, y) x ## y
#define CONCATENATE(x, y) CONCATENATE_IMPL(x, y)
#define ATEXIT(f) int CONCATENATE(atexit, __LINE__) __attribute__((__cleanup__(f))) = 0
int function(void) {
ATEXIT(cleanup1); // These are executed in reverse order, i.e.
ATEXIT(cleanup2); // cleanup2 will run before cleanup1.
}