工作2年,干了一年ARM平台嵌入式,一年后台,总结下这两年开发中调试的经验。我把调试手段分成2种:打印日志和用工具分析。因为平时主要开发在Linux平台,就以GDB为例

一、打印日志

1. 合理设置日志级别

一般的日志库都会有日志级别,合理使用能避免因线上环境的日志打印过大而导致的磁盘占用过高,搜索日志耗时太长,因为日志大小超过设置值,导致一天打印日志数过多等问题。线上环境的日志一般需要以下级别:

Info,表示业务走到关键点时候的变量信息,队列消费数目,等待处理数目这些用于定位业务是否正常,分析程序性能所需要的指标信息

Warn,正常情况下程序不应该出现这种状态,但不是致命错误

Error,程序异常了,或者已经挂掉了

而测试环境,功能测试时可以把日志设置成Debug级别,最后代码提交时,可以带有Debug级别的日志,但务必保证留下的日志精简,明确。一个精简的调试日志,可以替代大部分函数内注释

2. 善于运用内置的调试宏

c++提供的几个宏:__FILE__ , __FUNCTION__ , __LINE__ 帮助定位代码位置

void Foo(){
//error here
Log.Error<<__FUNCTION__<<" is errors in Line["<<__LINE__<<"] varable is "<<var<<endl;
}

当然,有的库自带了这些信息

3. 日志划分

多线程下,一个模块可能有多个业务流程。日志划分时最好按照业务,或者模块划分。比如数据库操作的一个日志,和消息中间件通信的一个日志。便于日志归档管理

4. 避免滥用日志

日志级别设成info时,debug是不会打的。但这并不代表这条debug级别的日志不会消耗cpu的资源。看下面这个例子

log.debug("fun[%s] return [%d]", __func__, fun());

这条日志不会被打印,但仍然会执行,并且消耗cpu。理由有2点。

  1. 日志的接口函数被调用了,只是判断级别不够,不输出到日志文件。
  2. fun()作为函数的实参传递,fun先被掉用,再将结果传给日志接口

所以一定不能觉得测试的日志反正线上不会显示,就可以随意打印。

总结起来,日志需要注意以下3点

  • 一条日志描述清楚when,what,where信息
  • 在可能出现问题的地方打日志,通过其他日志能推断出信息的地方,无需再打日志
  • 调用日志打印接口时,不要调用函数

二、GDB调试以及coredump分析

1. ELF文件

ELF(Executable Linkable Format)是COFF(Common File Format)的格式变种。系统中采用ELF的有以下几种

  • 可重定位文件
  • 可执行文件
  • 共享目标文件
  • 核心转储文件(Core Dump File)

这4类文件在Linux中可以通过`file [file name]`看出属于哪一种。核心转储文件就是我们常说的core文件,当程序意外终止时,系统将进程的所有地址空间以及终止信息存在该文件中。所以我们需要对ELF有所了解,才能正确分析core文件。有的系统限制了core文件的大小,需要ulimit -a看一下,然后设置成需要的值,例如ulimit -c unlimit

2.处理目标文件的工具

  • AR:创建静态库,插入删除列出和提取成员
  • STRIP:列出一个目标文件中所有可打印的字符串
  • NM:列出一个目标文件的符号表中定义的符号
  • SIZE:列出目标文件中节的名字和大小
  • READELF:显示一个目标文件的完整结构,包括ELF头中编码的所有信息。包含SIZE和NM的功能
  • OBJDUMP:所有二进制工具之母,能够显示一个目标文件中所有的信息。最大的作用是反汇编.text节中的二进制指令
  • LDD:列出一个可执行文件在运行时需要的共享库

常用的参数举例:

readelf -h [file] 查看elf头部信息

readelf -S

objdump -d -j [section] [file]

3. gdb的使用

(图摘自CSAPP ch3.11)

产生coredump文件时分析步骤:

1. bt  查看程序crash位置,where也可以
2. `frame number` `up/down n`  到对应标号的栈帧
3. list +  查看代码
4. info locals  简化命令i locals。看栈变量、函数行
5. `print name_of_variable` or `p name_of_variable`  打印变量

需要注意的是,由于现在gcc编译器普遍开了优化,使源代码和生成的代码之间的映射更难看出。这些优化对程序性能有提升,却增加了调试的难度。当看不出时,需要结合日志和代码推断问题。

总结下c/c++的一些调试经验的更多相关文章

  1. (转)CMOS Sensor的调试经验分享

    CMOS Sensor的调试经验分享 我这里要介绍的就是CMOS摄像头的一些调试经验. 首先,要认识CMOS摄像头的结构.我们通常拿到的是集成封装好的模组,一般由三个部分组成:镜头.感应器和图像信号处 ...

  2. CMOS Sensor的调试经验分享

    转自:http://bbs.52rd.com/forum.php?mod=viewthread&tid=276351 CMOS Sensor的调试经验分享 我这里要介绍的就是CMOS摄像头的一 ...

  3. 调试经验--硬盘U菜

    调试经验--硬盘U菜 随着嵌入式设备功能的开发,随着对存储设备的需求:需要存储大量数据信息.需要在转储数据,U盘升级功能等.     在使用存储设备的过程中,我们遇到一些问题,也总结了些经验: 1.几 ...

  4. CMOS Sensor的调试经验分享【转】

    转自:https://blog.csdn.net/yapingmcu/article/details/37817727 转自:http://bbs.52rd.com/forum.php?mod=vie ...

  5. 总结OpenvSwitch的调试经验

    相信相信不少人在开始用OpenvSwitch(以下简称OVS)或者修改源码的时候,都不知道如何去调试,根据我的学习历程以及从网上搜集的资料做一个汇总. 一. 个人经验 从网上找相关资料,熟悉Openv ...

  6. 程序异常崩溃后用windbg辅助调试解决的经验 以及 堆栈问题调试经验

    1,程序异常崩溃后用windbg辅助调试解决的经验  状况:我的程序调用别人的库做 文件写入工作. 在这一过程中出现异常,程序崩溃. 经反复检查,认为自己的程序没有错,但无法判断在别人库里哪里有错. ...

  7. 17调试经验之串口读写flash协议

    一是设计功能 我的理解协议就是一个命令包,通过给出不同的控制命令,来调动不同的功能模块,实现不同的功能,如读数据,写数据,擦除等. 二设计过程 先看了尤老师的视频,主要讲了大致设计原理和总体框架,当然 ...

  8. 电机三环pid控制及调试经验

    一.伺服电机的双环pid 双环pid在正常底盘运动的控制中已经足够了,但是对于双轴云台的控制来说,双环pid的云台控制的响应速度是远远不够的,所以加入了电流环的控制. 两篇大佬的文章--这是我学习pi ...

  9. win10 下visual studio 2015 在调试模式下不能跟踪源文件

    win10 下visual studio 2015 在调试模式下不能跟踪源文件,只要一调试就会关闭(隐藏)打开的文档,非常不方便.经过一番折腾,发现是配置的问题. 如果安装多个版本的VS,请删除对应版 ...

随机推荐

  1. 需求:一个页面中需要用到多个字典数据。用于下拉选项,同时,需要将其保存为json格式。以便于key,value的相互转换。记录在实现过程中踩的坑

    本文涉及到的知识: Promise,all()的使用 js处理机制 reduce的用法 map的用法 同步异步 需求: 一个页面中需要用到多个字典数据.用于下拉选项,同时,需要将其保存为json格式. ...

  2. [JavaWeb基础] 027.JAVA中使用Axis搭建webservice-示例实现(二)

    在上面的一个文章中,我们介绍了如何搭建Axis2的环境,也就是在MyEclipse中加入Axis的开发插件,那么,准备工作做好了之后,下面我们就用上一章的工具去搭建一个WebService的简单例子. ...

  3. [PHP学习教程 - 数字]001.数字补0(Num padding)

    引言:在日常工作中,经常要用到数字前后补0的操作,如:日期格式yyyy-MM-dd等等. 在php中有多种前后填充函数——今天,我们就介绍常用的两种,实现数字补零: str_pad sprintf 大 ...

  4. [工具推荐]003.Tortoisegit使用教程

    Git简介:       Git是一款免费.开源的分布式版本控制系统,用于敏捷高效地处理任何或小或大的项目,是一个开源的分布式版本控制系统,用以有效.高速的处理从很小到非常大的项目版本管理.Git 是 ...

  5. 初步理解 MySQL数据库

    个人博客网:https://wushaopei.github.io/    (你想要这里多有) 1. 索引是做什么的? 索引用于快速找出在某个列中有一特定值的行.不使用索引,MYSQL必须从第1条记录 ...

  6. (Java实现) 洛谷 P1025 数的划分

    题目描述 将整数n分成k份,且每份不能为空,任意两个方案不相同(不考虑顺序). 例如:n=7,k=3,下面三种分法被认为是相同的. 1,1,5; 1,5,1; 5,1,1. 问有多少种不同的分法. 输 ...

  7. Java实现 LeetCode 677 键值映射(字典树)

    677. 键值映射 实现一个 MapSum 类里的两个方法,insert 和 sum. 对于方法 insert,你将得到一对(字符串,整数)的键值对.字符串表示键,整数表示值.如果键已经存在,那么原来 ...

  8. Java实现 LeetCode 661 图片平滑器(暴力)

    661. 图片平滑器 包含整数的二维矩阵 M 表示一个图片的灰度.你需要设计一个平滑器来让每一个单元的灰度成为平均灰度 (向下舍入) ,平均灰度的计算是周围的8个单元和它本身的值求平均,如果周围的单元 ...

  9. Java实现 蓝桥杯VIP 算法训练 P1102

    定义一个学生结构体类型student,包括4个字段,姓名.性别.年龄和成绩.然后在主函数中定义一个结构体数组(长度不超过1000), 并输入每个元素的值,程序使用冒泡排序法将学生按照成绩从小到大的顺序 ...

  10. Java实现 蓝桥杯VIP 算法提高 大数加法

    算法提高 大数加法 时间限制:1.0s 内存限制:256.0MB 问题描述 输入两个正整数a,b,输出a+b的值. 输入格式 两行,第一行a,第二行b.a和b的长度均小于1000位. 输出格式 一行, ...