在程序的编写与测试中,调试功能是非常重要的,很多时候我们需要一步步的调试与观察才能找到一些隐藏很深的bug,所以要对编译器的调试选项有一些了解,下面我们首先看一下编译器的调试选项都有哪些。
表1编译器的调试选项
选项
别名
优化的效果
--symdebug:dwarf
-g
-g是默认选项,在缺省情况下,大多数程序和库都是带调试符号(gcc参数-g)编译的。当调试一个带调试符号的程序时,调试器不仅能给出内存地址,还能给出函数和变量的名字。产生符号调试信息并不会影响程序的优化效果。
注:DWARF是一种很复杂的二进制文件格式,它和和STAB格式是使用最广泛的两种可执行和链接格式(ELF)。DWARF(使用任意记录格式调试)是面向ELF文件的一种较新的格式。创建该格式是为了弥补STAB中的一些缺陷,从而能够提供更详细、更简便的数据结构描述、变化的数据移动和复杂的语言结构,比如C中的语言结构。调试信息存储在对象文件的各个部分中。这种格式是可执行程序与源代码之间关系的简单表示,为了便于调试器对该关系进行处理。对此感兴趣的网友可以搜索《The DWARF Debugging Standard》标准仔细阅读,或者参考IBM的网页说明http://www.ibm.com/developerworks/cn/opensource/os-debugging/。
--symdebug:coff
使用交替的STABS调试格式来使能符号调试;调试信息的传统格式被称为STAB(符号表)。STAB调试格式是一种记录不完整的半标准格式,用于调试COFF和ELF对象文件中的信息。调试信息是作为对象文件的符号表的一部分进行存储的,因此复杂性和范围是有限的。
使用这种格式的目的是为了与一些很古老的调试器或者用户自定义的调试工具进行兼容,因为这些工具往往不兼容新的DWARF格式。
使用这个选项有可能会对程序的优化造成影响,因为为了使用STAB格式下的调试功能,有些代码需要被保留而无法优化。
--symdebug:none
禁止所有的符号调试信息。
不建议使用这个选项,因为它禁用了调试功能,并使得程序的性能分析变得非常困难。比如说我们测算代码的运行时间的时候,就需要在代码中插入断点使用调试功能完成测算。
--symdebug:profile_coff
使用交替的STABS调试格式来进行程序的性能分析。
在CCS里,使用这个选项可以在函数级别上插入断点并估算程序运行时间,但是不能使用单步调试功能。
--symdebug:skeletal
已经废弃的参数,不再建议使用,即使使能也不产生任何效果。
--optimize_with_debug
-mn
已经废弃的参数,不再建议使用,即使使能也不产生任何效果。
--symdebug:keep_all_types
这是一个编译器的高级调试选项,它用来保持未参考的类型信息。也就是说,使能这个选项之后,可以在调试时观察定义包含在COFF可执行文件中,但是没有被任何地方引用的符号(默认情况下这样的符号是不具有调试信息的,使能调试之后变可以进行一些调试相关的工作了)。
调试选项看起来非常复杂,不过通过前面几次的讲解也可以看出,这些名字特别长,并且一般情况下没有别名(缩写名)的选项,基本都是输入高级选项,对于一般使用者来说的话,我们的主要目的不是去关心它编译过程中有多么复杂的信息,只要利用它的结果,所以一个-g选项就能满足大多数情况的使用了。
然后针对初学者经常遇到的找不到头文件或者宏定义的问题,这个貌似是大多数初学者在新建工程时、添加完文件然后编译程序时都会遇到的:明明看见头文件它就在那里了,可是编译器就是不认识它;或者在CCS里面已经打开了头文件能看到内容了,可是编译器一直在提示xxx.h头文件打不开。因为头文件里定义了各种各样的变量、结构体、宏定义甚至函数声明等,所以一个头文件找不到的话往往会带来几十个上百个“未定义”相关的错误。在此我们就看一下编译器的包含选项,理解了它的使用方法,自然就不会再遇到类似的问题了。
表2 编译器的包含选项
选项
别名
优化的效果
--include_path=directory
-I
用来定义引用头文件时#include中文件的路径。这个不难理解,基本上就是指代我们在程序中引用头文件时制定的头文件的路径。初学者经常遇到的问题就是头文件找不到,然后出现一大堆的调试错误,所以要掌握这个选项。
在引用头文件时,如果使用双引号”xxx.h”进行引用的话,则编译器在编译时按照下面的顺序和路径依次进行寻找:
1.从任何引用了xxx.h的源程序所在的文件夹里进行搜索。所以在编译时如果提示缺失xxx.h文件,最快捷的方法就是找到这头文件把它放在源程序所在的文件夹里(当然这样不利于有条理地管理工程文件)。
2.从-I参数中所制定的路径里面搜索。
3.从安装CCS时生成的C2000_C_DIR环境变量指向的路径里面搜索。
在引用头文件时,如果使用尖括号<xxx.h>进行引用的话,则编译器在编译时按照下面的顺序和路径依次进行寻找:
1.从-I参数中所制定的路径里面搜索。
2.从安装CCS时生成的C2000_C_DIR环境变量指向的路径里面搜索。
观察两种头文件引用方法的共同点,我们可以得出,除了系统自带的头文件,例如<math.h>这样的我们不需要管它之外,我们自己定义和使用的头文件一定要使用-I参数把路径定义好,就不会再有什么头文件打不开、不存在之类的错误了。那如果头文件有多个路径进行存储怎么办呢?只要多次使用-I参数就行了,例如:
-i"..\..\DSP2833x_headers\include" -i"..\..\DSP2833x_common\include"
--preinclude=filename
在编译开始时指定源程序的文件名filename。这个选项主要用来建立标准的宏定义。这些文件名的搜索也按照-I定义的路径来进行,并按照制定的顺序编译。