在C中跟踪函数调用

evr*_*rn0 8 c debugging trace design-patterns

我正在为用C编写的自动化系统开发一些模块,我需要使用硬件执行大量工作.我没有看到调试事物而不是跟踪日志的简单方法(如传统方法).所以我正在寻找一个记录函数调用的好习惯.至少调用和返回值的顺序.

它在应用程序中执行的方式非常简单,并且实际上使用不相关的构造来污染代码

int function (int param){
   if(trace_level & LOG_FCALLS){
      writelog("Entering function()");
   }

   /* something useful */

   if(trace_level & LOG_FCALLS){
      writelog("Exit from function()=%d", ret);
   }
}
Run Code Online (Sandbox Code Playgroud)

我决定使用一个可以完成所有脏工作的宏.现在看起来像这样

#define LOG_E(fn) const char *__fname=fn;  printf("LOG: Entry to %s\n",__fname)
#define return(ret)     printf("LOG: Exit from %s()=%d\n",__fname,ret)

int testFunc(){
   LOG_E("testFunc");

   /*do useful things */

   return(ret);
}
Run Code Online (Sandbox Code Playgroud)

我看到了这段代码的问题

  1. 我正在覆盖return语句,它需要一直写return(ret)而不是return ret.很容易忘记这个问题.

  2. 我在我的宏中定义字符串变量.我知道__func__宏存在于C99中,但不幸的是,我的编译器不支持这个宏或任何其他相关的宏.

  3. 如何记录函数参数的值?

我很确定这不是一个新问题,我不是第一个面对它的人.我也知道AOP的事情,但代码检测是我的系统不可接受的解决方案,我没有发现任何可能与我的编译器.

所以我正在寻找一个好主意如何以最优雅的方式实现跟踪.

我的环境:传统代码,C,Watcom 10.x,实时操作系统

Lun*_*din 5

执行此操作的超级严谨,专业的方法是创建一个单独的调试/测试项目,该项目完全独立于生产代码.它是这样的:

  • 确保在生产代码上有备份/提交.
  • 在硬盘驱动器上制作生产代码的硬拷贝.这将成为您的测试项目.
  • 创建一个.txt日志文件,您可以在其中编写要记录的每个函数的完整签名,例如:

    int function (int param)
    float function2 (void)
    ...
    
    Run Code Online (Sandbox Code Playgroud)
  • 创建一个小的PC程序/脚本,将上述.txt文件作为输入,然后在源代码中搜索匹配的函数定义行.然后,PC程序将根据原始代码生成一个新的.c文件,在此{之前和之后,它将调试日志代码插入所需的函数中}.你需要几个小时的时间来完成这样的计划.
  • 使用脚本创建的修改后的源代码链接测试项目.

上面的方法是我自己在关键任务软件上做的,你有安全标准(MISRA,代码覆盖等)的要求,说没有允许在最终产品中执行的代码.

此方法可确保生产代码的完整性,并确保测试/调试代码不会将任何意外错误添加到程序中.它还使生成代码中的编译开关等杂乱无章.并且您将不会在您的项目中保留任何旧的调试代码而您忘记删除(否则我总是在我的程序中忘记一些调试代码片段).


Gya*_*ain 1

#if defined(DEBUG_BUILD)
#  define START_FUNCTION if(trace_level & LOG_FCALLS){writelog("+++ %s()", __func__)
   }
#  define END_FUNCTION if(trace_level & LOG_FCALLS){writelog("--- %s()", __func__)
#elif defined (TIMING_BUILD)
#  define START_FUNCTION  WRITE_TIMED_LOG("+++")
#  define END_FUNCTION WRITE_TIMED_LOG("---")
#else
#  define START_FUNCTION
#  define END_FUNCTION
#endif
int function (int param){
   START_FUNCTION;
   ...
   if(error_occurred) {
     END_FUNCTION;
     return errror_code;
   }
   ...
   END_FUNCTION;
   return 42;
}
Run Code Online (Sandbox Code Playgroud)