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 DEBUGprintf("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 。省略#define DEBUG情况下。如下:
加了-DDEBUG:

不加-DDEBUG:


优点:方便简单不复杂
缺点:每条调试语句都被预处理指令包含,造成代码膨胀;无法方便地打印文件信息和行信息,并且不利于生成日志文件
1-4自定义调试日志打印函数
1-4-1简易函数
我们可以用自己的函数来实现更加智能的日志打印的函数,在前面添加代码如下:

#include<stdio.h>
#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语言库中的 FILE,LINE,FUNCTION 这三个宏定义,分别代表的就是当前的文件名file,行数line,函数名function。我们使用宏定义的方法把这三个加进去,再将logd函数的参数增加这三个,就可以打印这些信息了。代码如下:

#include<stdio.h>
#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-
以上内容转载于https://blog.csdn.net/weixin_42534168/article/details/115699275
关于zlog库的快速使用教程

tao@ubuntu:~/study/test$ git clone  https://github.com/HardySimpson/zlog.git
正克隆到 'zlog'...
remote: Enumerating objects: 3264, done.
remote: Counting objects: 100% (3/3), done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 3264 (delta 0), reused 0 (delta 0), pack-reused 3261
接收对象中: 100% (3264/3264), 3.16 MiB | 4.76 MiB/s, 完成.
处理 delta 中: 100% (2329/2329), 完成.


切换到下载的zlog目录

tao@ubuntu:~/study/test$ ls
zlog
tao@ubuntu:~/study/test$ cd zlog/
tao@ubuntu:~/study/test/zlog$ ls
Changelog  COPYING  doc  INSTALL  makefile  README.md  src  test  TODO  tools

安装到系统

$ make
$ sudo make install



使用方法:代码+配置文件

因为打印可以配置格式,索引zlog库的使用就需要一个zlogname.conf的配置文件,在配置文件里面可以指定打印格式,等级,等等。。。

myzlog.conf配置文件介绍

由于配置文件格式比较丰富,条件也很多,所以,我在这里只提供一个最简单,最实用的配置文件可直接使用,想要详细了解可在最下面配置文件格式详细介绍。myzlog.conf文件是将打印日志输出到mytest.log文件中,可在mytest.conf文件查看日志。

打印等级

#默认打印等级: FATAL > ERROR > WARN > NOTICE > INFO > DEBUG


常用myzlog.conf配置文件内容

[global]
strict init = true
buffer min = 1024
buffer max = 2MB
rotate lock file = /tmp/myzlog.lock
default format = "%d.%us [%-6V] [%p:%F:%L] - %m%n"
file perms = 600#默认打印等级: FATAL > ERROR > WARN > NOTICE > INFO > DEBUG
#只有当打印等级大于等于DEBUG时才会打印输出#定义的myrule_class将会在函数dzlog_init("myzlog.conf", "myrule_class")中使用
[rules]
myrule_class.DEBUG        "mytest.log",10kb * 3 ~ "mytest.txt.#r"; #输出到mytest.log文件
# my_zlog.DEBUG >stdout; #打印输出到终端

测试代码

#include <stdio.h>
#include "zlog.h"int main(void)
{int ret;int d=10;char *s="world";ret = dzlog_init("myzlog.conf", "myrule_class"); //指定配置文件路径及类型名 初始化zlogif (ret) {printf("init failed\n");return -1;}//打印等级数值越低,等级越高dzlog_debug("debug");          //5dzlog_info("info,  %d %s",d,s); //4dzlog_notice("notice");           //3dzlog_warn("warn");            //2dzlog_error("error");          //1dzlog_fatal("fatal");          //0zlog_fini();     //释放zlogreturn 0;
}

编译

gcc main.c -lzlog

调试C语言程序-使用日志的方式相关推荐

  1. vc60如何输入c语言,vc60中如何编译运行及调试c语言程序.pdf

    VC++6.0中如何编译运行调试 C语言程序 1. 启动VC++6.0 (如下图) 2. 单个源文件的编译运行 例如下面的源代码 #include void main() { int i,sum=0; ...

  2. c语言vi运行编译文件,VC++6.0中如何编译运行及调试C语言程序文件.docx

    VC++6. 0中如何编译运行调试C语言程序 1?启动VC++6. 0 (如下图) [5>R?*16 00 P"! tptl tub go□賦星糸理技件□中出融Fz " 口仍 ...

  3. c语言如何编译及调试,中如何编译运行及调试C语言程序.doc

    中如何编译运行及调试C语言程序 VC++6.0中如何编译运行调试C语言程序 1.启动VC++6.0 (如下图) 2.单个源文件的编译运行 例如下面的源代码 #include void main() { ...

  4. 验08利用gdb工具调试c语言程序,实验4_C开发工具和系统函数

    实验四C开发工具和系统函数 (一)C语言开发工具 目的 1.掌握gcc.make.gdb工具 2.熟悉c语言 内容 1.编写一个c语言程序:输出两行文字"Linux下的c也不是太难嘛!&qu ...

  5. Visual Studio 2010 调试 C 语言程序

    转:http://woyouxian.net/c/using_visual_studio_write_pure_ansi_c_program.html 本篇文章讲述如何用微软的 Visual Stud ...

  6. 简单示例,VS2019调试C语言程序

    首先在这里先说一下小编使用的Visual Studio环境,如下图2019社区版,社区版是可以免费使用的,不过你的注册个账号登录,否则30天后会检测许可证失败. 在上一篇简单的C程序示例中关于创建C项 ...

  7. 【嵌入式1】Ubuntu系统下运行C语言程序以及用Makefile方式编程

    文章目录 一.设置网络参数 1.虚拟机网络适配器设置为NAT模式 2.确定网卡ip 3.设置NAT网络的端口映射 4.进行网络测试 二.用C语言编写一个简单的输出 hello word 的程序. 三. ...

  8. C语言程序的内存分配方式

    1.内存分配方式  内存分配方式有三种: [1]从静态存储区域分配.内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在.例如全局变量,static变量. [2]在栈上创建.在执行函数 ...

  9. 5个流水灯c语言程序,五种编程方式实现流水灯的单片机C程序

    <五种编程方式实现流水灯的单片机C程序>由会员分享,可在线阅读,更多相关<五种编程方式实现流水灯的单片机C程序(5页珍藏版)>请在人人文库网上搜索. 1.五种编程方式实现流水灯 ...

最新文章

  1. LeetCode Different Ways to Add Parentheses(递归,动态规划)
  2. 精简版开发工具使用手记(图解)
  3. Centos与Ubuntu
  4. win7查看隐藏文件_隐藏在电脑里の秘密,放在你眼前,你也发现不了,就是这么奥给力...
  5. mysql存中文_mysql数据库存储中文数据的解决办法
  6. oracle 未找到段的存储定义,Exp-00003 no storage definition found issue in oracle 11g (未找到段 (0,0) 的存储定义)...
  7. uView u-button修改样式
  8. 归并排序的java语言_归并排序 java语言
  9. python与txt文件查找,在Python中搜索TXT文件
  10. 线程 daemon java user,Java线程_守护线程和用户线程
  11. linux多线程编程介绍
  12. 【AI PC端算法优化】七,RGB和YUV图像颜色空间互转SSE优化
  13. 1037u处理器搭载文件服务器,悦升IVB 赛扬1037U工控主板 满足多行业需求
  14. 光合作用c3和c5变化语言叙述,浅议光合作用中C3和C5的含量变化
  15. python处理can协议文件_二、如何解决:python:Can't reopen .pyc file
  16. html锚点定位向下偏移,html锚点定位不准确问题
  17. 问卷分析之SPSS相关分析、相关系数矩阵(Pearson)
  18. PFSO-T5,一种OLED材料
  19. Git: Cannot update paths and switch to branch 'feature' at the same time.
  20. MSP430系列单片机实用C语言程序设计 张晞pdf

热门文章

  1. Java currentTimeMillis()方法介绍
  2. JS验证邮箱和手机号
  3. Python 数据库连接池
  4. 质因数的求解(C语言和C++)
  5. 谷歌浏览器的打印功能
  6. Redis操作 入门个人总结
  7. SpringBoot整合SpringSecurity实现权限控制(五):用户管理
  8. jfreechart实现动态图表
  9. Java 向上转型 向下转型 instanceof
  10. 【WinForm】设置TextBox只能输入整数或数字