zoukankan      html  css  js  c++  java
  • 【译文】 不同调试技术介绍

    原文地址: http://oopweb.com/CPP/Documents/DebugCPP/Volume/techniques.html

    这一部分介绍调试技术,包含了从阅读手册到使用工具的相关信息。

    使用编译器的特性
      一个好的编译器能够对你的代码做很多静态分析,该分析能够检查很多语义错误,比如类型不匹配、死代码等。对于GCC而言,有很多选项影响GCC静态分析做什么和展示什么。它主要有下面两类参数:

    Warning options  : GCC有很多warning 标志,很多是 “-Wphrase”这样的形式。你可以选择你感兴趣的添加到Makefile中(如果使用隐式规则,可以设置CFLAGS变量)。注意-Wall 只是包含了程序员们认为在多数情况想有用的选项。

    Optimisation flags : GCC可以设置不同的优化等级。其中一些可以触发对代码的流分析。通常情况下,建议使用-O2级别。

       GCC 部分 http://oopweb.com/CPP/Documents/DebugCPP/Volume/techniques.html 

    RTFM技术

    RTFM是Read The Fine Manual的缩写。你要保证花时间找了该任务相关的文档,比如工具(不只是编译器,还有make,预处理器和链接器)、库、算法的文档。通常你不需要知道文档的所用事情,但是你必须知道这些文档是干什么的,都是什么目的。 你应当能够区分教程和参考文档:
      教程只是使用示例的方法来教你怎么用。在一个教程中,传递idea 比咬文嚼字的信息重要!
          参考文档假设你已经熟悉了它的topic,现在你需要找一个特定问题的确切答案。好的参考文档是非常详尽的,通过元信息(内容目录,索引,交叉引用)使你能够快速找到想要的答案。在线超文本是参考文档的一个很方便的格式。

    printf() debugging
    这是我们最经常碰到的形式,我们使用printf打印信息来了解控制流和变量当时的值。但是这样做有很多弊端:

    1代码只是暂时加进去的,当前bug一旦解决就要删除。遇到下一bug,你又要添加相似的代码。你马上将看到有更好的方法添加调试信息。

    2这样做干扰了程序的正常输出,并且降低了程序的运行速度。

    3更重要的,它通常是没有帮助的。输出到stdout的信息是被缓存的,程序一旦crash,这些信息就丢失了。因此,你很可能错过了重要的信息,误导你到错误的地方寻找bug。
    如果你考虑使用pringf调试,下面是几个建议:

    1把错误输出到stderr,stderr是没有缓存的,这样就避免了crash时信息的丢失

    2不要直接使用printf,定义一个宏使用,这样你就可以很轻松的打开或者关闭调试代码

    3使用debugging level来管理调试信息

    下面是一个很好的实例:

    #ifndef DEBUG_H
    #define DEBUG_H
    #include <stdarg.h>
    
    #if defined(NDEBUG) && defined(__GNUC__)
    /* gcc's cpp has extensions; it allows for macros with a variable number of
       arguments. We use this extension here to preprocess pmesg away. */
    #define pmesg(level, format, args...) ((void)0)
    #else
    void pmesg(int level, char *format, ...);
    /* print a message, if it is considered significant enough.
          Adapted from [K&R2], p. 174 */
    #endif
    
    #endif /* DEBUG_H */
            
    File debug.c:
    
    #include "debug.h"
    #include <stdio.h>
    
    extern int msglevel; /* the higher, the more messages... */
    
    #if defined(NDEBUG) && defined(__GNUC__)
    /* Nothing. pmesg has been "defined away" in debug.h already. */
    #else
    void pmesg(int level, char* format, ...) {
    #ifdef NDEBUG
        /* Empty body, so a good compiler will optimise calls
           to pmesg away */
    #else
            va_list args;
    
            if (level>msglevel)
                    return;
    
            va_start(args, format);
            vfprintf(stderr, format, args);
            va_end(args);
    #endif /* NDEBUG */
    #endif /* NDEBUG && __GNUC__ */
    }

    断言 :防守式编程
    代码中有很多条件判断,对于函数,有前置条件和后置条件。使用assert对这些添加判断,保证程序的正确。 asset是一个宏,你可以在编译的时候使用-DNDEBUG选项来关闭。

    ANWB 调试
    ‘ANWB Debugging’是基于一个简单的原则: 学习东西的最好的方式是教授它们。
    你找到一个,最好是不相关的,旁观者,向她解释你的代码是如何工作的。这迫使你重新思考你的假设,解释究竟发生了什么事,很多时候通过这种方式找到你的问题的原因。

  • 相关阅读:
    02-05 flutter provider的使用
    02-04 flutter 构造函数总结
    02-03 flutter异步
    02-02dart语法
    02-01dart语法
    01-01 iOS内存对齐、内存对齐算法
    01-02 iOS kvo、kvc
    01-03 category 原理概述
    多线程编程 (2) -NSOperation
    IOS基本控件属性
  • 原文地址:https://www.cnblogs.com/ridox/p/4365053.html
Copyright © 2011-2022 走看看