C语言中的范围保护

C语言中的范围保护,c,scope,guard,C,Scope,Guard,我想在C中使用scope guard来进行分析 我想知道我花了多少时间在一个函数上。以下是我的工作: int function() { tic(); ... do stuff ... if (something) { toc(); return 0; } toc(); return 1; } 每次退出函数时,我都需要放置一个toc语句。我想这样做,而不必复制粘贴到任何地方。有没有一种通用的方法可以做到这一点,使用宏或其他什么? 另外,我不想改

我想在C中使用scope guard来进行分析

我想知道我花了多少时间在一个函数上。以下是我的工作:

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();