我正在为用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);
}
}
我决定使用一个可以完成所有脏工作的宏。现在它看起来像这个
#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);
}
我看到了这段代码的问题
我覆盖了return语句,需要一直写return(ret)
而不是return ret
。很容易忘记这个问题。
我在宏中定义字符串变量。我知道C99中存在__func__
宏,但不幸的是,我的编译器不支持此宏或任何其他相关宏。
如何记录函数参数的值?
我很确定这不是一个新问题而且我不是第一个面对它的人。我也知道AOP的事情,但代码检测对我的系统来说是不可接受的解决方案,而且我还没有发现用我的编译器做任何事情。
所以我正在寻找一个好主意如何以最优雅的方式实现跟踪。
我的环境: 传统代码,C,Watcom 10.x,实时操作系统
答案 0 :(得分:5)
执行此操作的超级严谨,专业的方法是创建一个单独的调试/测试项目,该项目完全独立于生产代码。它是这样的:
创建一个.txt日志文件,您可以在其中编写要记录的每个函数的完整签名,例如:
int function (int param)
float function2 (void)
...
{
之后和}
之前,它将调试日志记录代码插入到所需的函数中。制作这样的节目需要几个小时的时间。上述方法就是我自己在任务关键型软件上的表现方式,在这些软件中,您有安全标准(MISRA,代码覆盖等)的要求,即不允许在最终产品中执行任何代码。
此方法可确保生产代码的完整性,并确保测试/调试代码不会向程序添加任何意外错误。它还使生成代码中的编译开关等杂乱无章。并且您不会在项目中保留任何旧的调试代码而您忘记删除(否则我总是在我的程序中忘记了一些调试代码片段。)
答案 1 :(得分: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;
}
答案 2 :(得分:0)
这适用于MS Visual C.对于不同的数据类型(或没有),您将需要不同版本的return
宏。
#include <stdio.h>
#define TRACING
#ifdef TRACING
#define LOG_E printf("Func: %s\n", __FUNCTION__);
#define LOG_R printf("Exit: %s\n", __FUNCTION__);
#define LOG_I(ival) printf("Exit: %s %d\n", __FUNCTION__, ival);
#else
#define LOG_E
#define LOG_R
#define LOG_I(ival)
#endif
int main(void){
int retval = 0;
LOG_E
printf("Hello world!\n");
LOG_I(retval)
return retval;
}
输出:
Func: main
Hello world!
Exit: main 0
答案 3 :(得分:0)
您可以自定义编译器来处理它。如果使用MELT进行编译,则可以使用GCC(自定义gcc
编译器)。
也许你可以自定义openwatcom(或者付一些 OpenWatcom 专家来做这件事)......