便携式仪器仪表

时间:2012-08-08 14:42:31

标签: c instrumentation

GCC有一个关于检测的很好的功能,它允许你在每次调用函数时或每次函数返回时调用例程。

现在,我想创建自己的系统,使其可以移植到其他编译器,并允许工具化我想要的功能(可以改变参数的数量),所以我在两种情况下考虑两种情况。我正在考虑制作某种类型的配置文件,它只能通过define子句激活。

#define FUNCT(t,function_name,...)   \
    (t) function_name(...) { \
        (void) *func_pointer = &(function_name); \
        start_data(func_pointer, myclock());

#define RETURN(x) {stop_data(func_pointer, myclock()); return (x);}

FUNCT(BOOL, LMP, const int prof, const int nmo))
    if (nmo <= 5 ||
        prof > (prof_l / 3)) {
        .... do long operations....
        RETURN(FALSE);
    }
    ... do more....
    RETURN(TRUE);
}

但我无法让它发挥作用。有人可以帮我弄这个吗?或者这是一项艰巨的任务吗?

我想到的其他选择是让函数在没有宏的情况下声明,如果无论如何知道函数指针而不知道它的名字,就像在VB中调用一个Form with Me一样,它是一个通用别名。有可能吗?

3 个答案:

答案 0 :(得分:3)

使用gcc -E调试您的宏。使用您发布的代码:

$ gcc -E t.c
# ... skip stuff ....

(BOOL) LMP(...) { (void) *func_pointer = &(LMP);
                  start_data(func_pointer, myclock());)
    if (nmo <= 5 ||
        prof > (prof_l / 3)) {
        .... do long operations....
        {stop_data(func_pointer, myclock()); return (FALSE);};
    }
    ... do more....
    {stop_data(func_pointer, myclock()); return (TRUE);};
}

(我添加了一些空格以使其可读。)

你可以立即看到两个问题:函数参数没有像你想象的那样得到扩展,并且在某个地方还有一个额外的)

要获取展开的可变参数,请使用__VA_ARGS__,而不是...。迷路)位于呼叫站点。

所以:

#define FUNCT(t,function_name,...)   \
    (t) function_name(__VA_ARGS__) { \
        (void) *func_pointer = &(function_name); \
        start_data(func_pointer, myclock());

#define RETURN(x) {stop_data(func_pointer, myclock()); return (x);}

FUNCT(BOOL, LMP, const int prof, const int nmo)
    if (nmo <= 5 ||
        prof > (prof_l / 3)) {
        .... do long operations....
        RETURN(FALSE);
    }
    ... do more....
    RETURN(TRUE);
}

至于这是否值得尝试(变量宏随附C99,并非所有编译器都实现了该标准,并且支持可能因编译器而异),我不确定。您可能最好使用每个编译器的本机分析工具 - 您可以获得更好的结果,希望减少开销。

答案 1 :(得分:1)

在主叫侧而不是功能侧更容易检测功能。宏可以与函数同名。在某处声明你的替换功能

double myfunc_wrapper(int someArg) {
  double ret = 0;
  // do something before
   ...
  // now call it
  ret = (myfunc)(someArg);

  // Then do something after
  ....
  return ret;
}

只是确保将()置于调用本身以确保始终调用函数而不是宏。

然后使用宏“重载”你的函数

#define myfunc(...) mfunc_wrapper(__VA_ARGS__)

有了这个想法,你可以在你所在的编译单元中动态替换你的函数。

答案 2 :(得分:0)

除了Mat之外,使用#define RETURN(x) {...}

还存在一个人体工程学问题
if (test)
  RETURN (TRUE);
else
  RETURN (FALSE);

将评估为

if (test)
  {...}
;           // <syntactical error
else
  {...}
;