调试C语言程序-使用日志的方式

1自定义日志调试

1-1引入
#include <stdio.h>
int fact(int n){
    int i,f=1;
    for( i=1; i<=n; i++){
       f += i;
    }
    return f;
}
int main(){
    printf( "4!=%d\n", fact(4) );
    return 0;
}

输出结果为:4!=11

与预期的结果不同,因此我们要对程序进行调试

我们在调试程序时,输出调试信息(又称为”打桩”或者”插桩”)是一种普遍、有效的方法。

我们输出的信息通常包括行号、函数名、程序变量等。

但是当我们调试结束之后,那些调试语句会影响程序输出时的美观和清晰,因此很多情况下我们都要手动把那些用来打印调试信息的语句删除或者注释掉。在大的项目中,这样做是很麻烦的。因此,我们要想办法来简化这些工作。

1-2传统手工日志:printf

也就是直接输出调试信息。

在上面的程序的函数fact中插入一条输出信息:

#include <stdio.h>
#include <stdio.h>
int fact(int n){
    int i,f=1;
    for( i=1; i<=n; i++){
       f += i;
       printf("i=%d ; f=%d\n", i, f);
    }
    return f;
}

输出的信息如下:
在这里插入图片描述
由此我们看出来是 f+=i这句话错了,应该改为 f*=i

改正之后再测试一下,就没啥问题了。

优点:简单,适合新手,通俗易懂

缺点:调试完之后要删除或注释掉调试的语句很麻烦,尤其是当项目庞大,调试增多时;无法方便地打印文件信息和行信息,并且不利于生成日志文件

1-3预处理封装printf

在每个调试语句用#ifdef包含,代码如下:

#include <stdio.h>
#define DEBUG
int fact(int n){
    int i,f=1;
    for( i=1; i<=n; i++){
       f += i;
    #ifdef DEBUG
       printf("i=%d ; f=%d\n", i, f);
    #endif
    }
    return f;
}
int main(){
    printf( "4!=%d\n", fact(4) );
    return 0;
}

如果DEBUG这个宏有定义,那么就执行这个#ifdef里面的语句。如果这个宏没有定义,那就不执行这里面的语句。因此,当我们调试结束之后,只需要把最前面定义的#define DEBUG删掉就可以了,而不需要把每条打印语句全都删掉,这样就方便了许多。

并且,gcc为我们提供了一个编译选项,因此用不着#define DEBUG这条定义语句。只要在gcc编译的时候加上-DDEBUG,注意有两个D。它就会自动帮我们定义这个DEBUG。如下:

加了-DDEBUG:
在这里插入图片描述
不加-DDEBUG:
在这里插入图片描述
优点:方便简单不复杂

缺点:每条调试语句都被预处理指令包含,造成代码膨胀;无法方便地打印文件信息和行信息,并且不利于生成日志文件

1-4自定义调试日志打印函数
1-4-1简易函数

我们可以用自己的函数来实现更加智能的日志打印的函数,在前面添加代码如下:

#ifdef DEBUG
#include <stdarg.h>
logd(const char *format, ...) {
	va_list argPtr;
	int count;
	va_start(argPtr, format);                  /*  获取可变参数列表  */
	fflush(stdout);                            /*  强制刷新输出缓冲区  */
	count = vfprintf(stderr, format, argPtr);  /*  将信息输出到标准出错流设备  */
	va_end(argPtr);                            /*  可变参数列表结束  */
}
#else
int logd(const char *format, ...) {

}
#endif
int fact(int n) {
	int i,f=1;
	for( i=1; i<=n; i++) {
		f += i;
		logd("i=%d ; f=%d\n", i, f);
	}
	return f;
}
int main() {
	printf( "4!=%d\n", fact(4) );
	return 0;
}

这样就可以通过资格自定义的打印函数来打印调试日志。仍然是在gcc编译时添加-DDEBUG来控制是否打印日志。如下:
在这里插入图片描述

1-4-2添加打印信息

但是,这样写,好像还缺点什么。如果能在打印的时候加上一些信息就好了,比如文件信息,函数信息,以及行的信息。因此,这里就用到了C语言库中的 FILELINEFUNCTION 这三个宏定义,分别代表的就是当前的文件名,行数,函数名。我们使用宏定义的方法把这三个加进去,再将logd函数的参数增加这三个,就可以打印这些信息了。代码如下:

#ifdef DEBUG
#include <stdarg.h>
logd(const char* filename, int lines, const char* functions,const char*format, ...) {
	printf("调试日志 --- 在文件: %s 中, 在第 %d 行, 在函数 %s中 ---",filename,lines,functions);
	va_list argPtr;
	int count;

	va_start(argPtr, format);                  /*  获取可变参数列表  */
	fflush(stdout);                            /*  强制刷新输出缓冲区  */
	count = vfprintf(stderr, format, argPtr);  /*  将信息输出到标准出错流设备  */
	va_end(argPtr);                            /*  可变参数列表结束  */
}
#else
int logd(const char *format, ...) {

}
#endif
#define LOGD(FORMAT,...) logd(__FILE__,__LINE__,__FUNCTION__,FORMAT,##__VA_ARGS__)
int fact(int n) {
	int i,f=1;
	for( i=1; i<=n; i++) {
		f += i;
		LOGD("i=%d ; f=%d\n", i, f);
	}
	return f;
}
int main() {
	printf( "4!=%d\n", fact(4) );
	return 0;
}

仍然是用gcc中的-DDEBUG控制是否打印日志。打印如下:
在这里插入图片描述
优点:日志信息清晰明了

缺点:无法将日志保存成文件

1-4-3写到日志文件中去

因此,我们再进行微调,把打印的信息写入到一个当前目录下名为 “log.txt” 的文件当中

修改代码如下:

#include <stdio.h>
#ifdef DEBUG
#include <stdarg.h>
int logd(const char* filename, int lines, const char* functions,const char*format, ...) {
	FILE*pFile = fopen("log.txt", "a+");
	fprintf(pFile,"调试日志 --- 在文件: %s 中, 在第 %d 行, 在函数 %s中 ---",filename,lines,functions);
	va_list argPtr;
	int count;

	va_start(argPtr, format);                  /*  获取可变参数列表  */
	fflush(stdout);                            /*  强制刷新输出缓冲区  */
	count = vfprintf(pFile, format, argPtr);  /*  将信息输出到标准出错流设备  */
	va_end(argPtr);                            /*  可变参数列表结束  */
}
#else
int logd(const char *format, ...) {

}
#endif
#define LOGD(FORMAT,...) logd(__FILE__,__LINE__,__FUNCTION__,FORMAT,##__VA_ARGS__)
int fact(int n) {
	int i,f=1;
	for( i=1; i<=n; i++) {
		f += i;
		LOGD("i=%d ; f=%d\n", i, f);
	}
	return f;
}
int main() {
	printf( "4!=%d\n", fact(4) );
	return 0;
}

效果如下:
在这里插入图片描述
在这里插入图片描述

打开log.txt看如下:
在这里插入图片描述

这样自定义的调试日志函数就完成了,只需要一句:LOGD(“xxx”,xxx,xxx,……); 就可以打印日志到文件中了

2,第三方日志库的使用

2-1一个小的第三方日志函数库
2-1-1安装

首先把两个文件复制过来:
在这里插入图片描述

然后在自己写的c文件中引入这两个,用include,像这样:

#include "log.h"
#include "log.c"

然后,就可以使用这样的语句打印日志:

LOG_PRINT(“xxx”,xxx,……);

例如刚才的fact.c这个求阶乘的文件:

#include <stdio.h>
#include "log.h"
#include "log.c"
int fact(int n) {
	int i,f=1;
	for( i=1; i<=n; i++) {
		f += i;
		LOG_PRINT("i=%d ; f=%d\n", i, f);
	}
	return f;
}
int main() {
	printf( "4!=%d\n", fact(4) );
	return 0;
}

在这里插入图片描述

就是这样使用LOG_PRINT();

就可以打印出很多的信息

参考:

[1] C语言 日志输出 测试运行时间(Windows、Linux平台)https://blog.csdn.net/u014644466/article/details/80311948

[2] C语言输出DEBUG调试信息的方法https://blog.csdn.net/zh1204190329/article/details/78594461

[3] C语言中几种输出调试信息的方法https://blog.csdn.net/thinkerABC/article/details/615378?depth_1-

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值