C语言调试小技巧

经常看到有人介绍一些IDE或者像gdb这样的调试器的很高级的调试功能,也听人说过有些牛人做工程的时候就用printf来调试,不用特殊的调试器。特别是在代码经过编译器一些比较复杂的优化后,会变得“难以辨认”,使用调试器也变得有些头疼。先举个简单的例子:

 1 #include <stdio.h>
 2
 3 int main(){
 4     int a[6], i, sum = 0;
 5     for(i = 0; i<6; i++)
 6         a[i] = i<<2;
 7     a[3] = 5;
 8     for(i = 0; i<6; i++)
 9         sum += a[i];
10     printf("sum = %d\n", sum);
11     return 0;
12 }

如果采用gcc(笔者的版本是4.7.3)编译,使用

1 gcc -O3 sum.c -S

来编译,可以查看到编译出来的汇编代码是:

 1     .file    "sum.c"
 2     .section    .rodata.str1.1,"aMS",@progbits,1
 3 .LC0:
 4     .string    "sum = %d\n"
 5     .section    .text.startup,"ax",@progbits
 6     .p2align 4,,15
 7     .globl    main
 8     .type    main, @function
 9 main:
10 .LFB24:
11     .cfi_startproc
12     subq    $40, %rsp
13     .cfi_def_cfa_offset 48
14     movl    $53, %edx
15     movl    $.LC0, %esi
16     movl    $1, %edi
17     xorl    %eax, %eax
18     call    __printf_chk
19     xorl    %eax, %eax
20     addq    $40, %rsp
21     .cfi_def_cfa_offset 8
22     ret
23     .cfi_endproc
24 .LFE24:
25     .size    main, .-main
26     .ident    "GCC: (Ubuntu/Linaro 4.7.3-1ubuntu1) 4.7.3"
27     .section    .note.GNU-stack,"",@progbits

说白了,就是gcc直接将main()优化成了这样:

1 int main(){
2     printf("sum = %d\n", 53);
3     return 0;
4 }

可想而知,对于这样优化的代码,调试器也会抓狂。

那么采用printf大法的好处就出来了,无论编译器如何优化,printf的输出总是正确的(编译器的优化总是保证程序效果不变),而且相较于调试器各种高深摸测的命令,printf的用法是程序猿的必备知识,所以利用printf来跟踪程序有的时候比调试器还要方便。虽然有的时候printf可能显得不那么安全,但你可换其它的安全的输出函数啊。其实printf大法的实质就是输出大法,直接在程序(当然是debug版的,或者说verbose功能下,release版当然…你懂的…)运行的时候屏显各种希望获取的运行时信息。

如何printf一个变量的值,我就不多说了,毕竟这是咱们程序猿的基本功。我是想要介绍一些调试用的宏:

宏名(每个宏名前后双下划线) 类型 意义
__FILE__ 字符串 当前程序名
__FUNCTION__ 字符串 当前函数名
__LINE__ 整数 当前行号(在源代码中的)
__DATE__ 字符串 被编译的日期
__TIME__ 字符串 被编译的时间
__STDC__ 整数(布尔) 如果编译器按照ANSI C来编译,为非零值;否则为0

使用这些宏来配合printf,可以做到很好的调试(当然也可以去做条件编译,不过本文暂不讨论这方面的应用)。

比如我可以定义一个BUG()如下:

1 #define BUG()    printf("Bug in function: %s (file: %s), @line: %d. It is compiled on %s  %s, %s ANSI C standard.\n", __FUNCTION__, __FILE__, __LINE__, __TIME__, __DATE__, __STDC__? "with" : "without");

当我觉得可能是对某函数因为参数指针p是NULL而使得程序崩溃,那么我可以在该操作中加入如下一句:

1 if(!p)
2     BUG();

这样如果真的因为p是NULL造成的程序崩溃的话,程序退出前会输出这个BUG在源代码中的位置,方便我们追踪它。至于为什么要输出编译的时间和日期,有的时候我们修改了.h文件,而往往在Makefile中我们是不写.h的依赖关系的,这样就可能会造成某种不一致,这时候输出代码编译的时间、日期就显得很有用了。最后那个ANSI C的检查,其实只是个以防万一而已。

转自:https://www.cnblogs.com/Leo_wl/p/3251234.html

原文地址:https://www.cnblogs.com/zzdbullet/p/9591292.html

时间: 2024-10-07 09:52:03

C语言调试小技巧的相关文章

&lt;python&gt;If 语句、while语句的规则和调试小技巧

If 语句的规则 1. 每一个“if 语句”必须包含一个 else. 2. 如果这个 else 永远都不应该被执行到,因为它本身没有任何意义,那你必须在 else 语句后面 使用一个叫做 die 的函数,让它打印出错误信息并且死给你看,这和上一节的习题类似,这样你 可以找到很多的错误. 3. “if 语句”的嵌套不要超过 2 层,最好尽量保持只有 1 层. 这意味着如果你在 if 里边又有了 一个 if,那你就需要把第二个 if 移到另一个函数里面. 4. 将“if 语句”当做段落来对待,其中的

JavaScript的兼容小坑和调试小技巧

JavaScript作为一种弱类型编程语言,入门简单,只要稍微注意一下IE方面的兼容性,就可以很好的使用它. 本文主要是对IE兼容的小坑和调试的小技巧进行举例分析,并给出解决方法. 1.var str: 与 var str = "":的区别 1 <script> 2 var Str1; 3 for (var i = 0; i < 3; i++) 4 { Str1 += "xxx" } 5 alert(Str1); 6 var Str2 = &quo

【调试】Visual Studio 调试小技巧(2)-从查看窗口得到更多信息(转载)

在使用Visual Studio开发调试程序时,我们经常需要打开查看窗口(Watch)来分析变量.有时在查看窗口显示的内容不是很直观.为了能从查看窗口的变量中得到更多的信息,我们需要一些小的技巧.下面是几个例子. 1. Windows消息 在开发调试界面程序时,我们经常需要查看消息的内容.当在查看窗口中,仅仅只显示出消息对应的整数值,我们并不能直观地知道究竟是什么消息.比如: 为了能让查看窗口显示出消息内容,我们只需要在变量名添加“, wm”的格式化后缀,就能显示消息的名字: 2. 句柄返回值

Firebug折腾记_(2)HTML&amp;CSS定位及调试小技巧

题外话 传统的开发我们是在编辑器操作代码保存,再到浏览器预览查看效果的; 而如今的firebug和chrome的内置调试器就不需要了..可以直接实时编辑且看到效果; 在调试中对代码的操作不会保存到本地实际代码中..是不是很赞!!; 定位HTML元素的三种方式 进入调试工具界面,按下"瓢虫"旁边的小鼠标,再进行网页元素的选择 默认快捷键,Ctrl + shift + C 鼠标移动到网页的某一块元素,鼠标右键,使用Firebug查看元素 HTML及CSS简单调试 ##HTML元素编辑 除了

C语言优化小技巧

在编写C语言程序后,经常需要对源码进行优化,以提高程序的运行效率,下面简述几个常用的优化技巧以供大家参考:1.C于代码在程序中的优化现在的C编译器会自动对代码进行优化,但这些优化是对执行速度和代码长度的平衡.如果要获得更小且执行效率更高的代码,需要程序员手工对代码进行优化. 2.变量类型的定义不同的数据类型所生成的机器代码长度相差很多,变量类型选取的范围越小运行速度越快,占用的内存越少.能够使用char(字符型)定义的变量,就不要使用整型(int)变量定义;能够使用整型变量定义的变量就不要用长整

调试小技巧

谷歌浏览器devtools 中的调试技巧 Ruby代码调试 如果不小心敲错了 ruby 代码,比如 create.js.erb中把?render?写成了?rennder?那么点击"发布评论"按钮是看不到报错信息的. 可以打开 devtools -> console ,这里可以看到一个 500 的错误.具体的错误内容可以到 network 下面,再次提交以下评论,就能看到了. 那么不知道错误信息,我们肯定很难修改,于是我们到如下位置查看错误信息: 如上是查看错误类型,那么具体的错误

CSS调试小技巧 —— 调试DOM元素hover,focus,actived的样式

最近学习html5和一些UI框架,接触css比较多,就来跟大家分享一下css中的一些调试技巧.之前做页面,css都是自己写的,所以要改哪里可以很快的找到,现在使用了UI框架,里面的样式是不可能读完的,所以就要通过调试来找到要修改的地方. 在调试CSS的时候,我们一般使用Chrome.Firefox.IE等浏览器自带的工具,快捷键都为F12.但是,我们要调试如hover的样式时,鼠标放上去才会显示,鼠标一走就看不到了,没办法看清楚css样式,还有就是浏览器自带的一些hover.foucs.acti

Jmeter脚本调试小技巧

使用Jmeter开发脚本时,在使用前置或后置处理器进行关联时,难免需要调试,这时可以使用Jmeter的Debug Sampler,示例如下: 第一步:设置后置处理器及需要提取的动态值 1.添加一个http sampler,访问:www.baidu.com; 2.给这个sampler添加一个后置处理器--Regular Expression Extractor,内容如下图: 第二步:提取第一步中后置处理器设置的值 1.在Thread Group下,添加一个Debug Sampler 2.设置Deb

Android——安卓调试小技巧(一)

在我们做完一个Activity之后,总是要看下效果才放心,但是面对虚拟器的启动慢,反应慢的两个痛点,我们总要寻找别的方法. 1,copy生成的APK文件安装 在我们选择Run As之后,会在bin文件夹下生产一个app的apk文件,我们可以拷贝出来,在未发布到google之前,发给测试人员使用. 或者是: 在这个apk文件上右键选择打开,之后会启用我电脑上默认的应用安装器(建议大家都在电脑上安装一个应用安装器),通过USB线安装到手机上.前提是,手机开启了调试模式. 2,DDMS+真机 玩儿过P