关键词:
经常看到有人介绍一些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
", 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
"
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
", 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.
", __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
c语言进阶学习笔记七程序执行+调试技巧(实用技巧篇)(代码片段)
文章目录一、程序执行篇①预处理详解②宏定义③define标识符字符串④define宏名(参数表)字符串⑤宏和函数对比二、调试技巧篇①什么是bug?②调试是什么?有多重要?③debug和release的介绍④windows环境调试介绍⑥如何写出... 查看详情
c语言学习笔记超级炫酷的c语言实用小技巧,学会这些隐藏技巧,早下班一小时(代码片段)
C语言常常让人觉得它所能表达的东西非常有限。它不具有类似第一级函数和模式匹配这样的高级功能。但是C非常简单,并且仍然有一些非常有用的语法技巧和功能,只是没有多少人知道罢了。一、指定的初始化很多人都... 查看详情
vs环境下的调试小技巧(代码片段)
debug与release的区别debug通常称为调试版本release称为发行版本,在代码大小和速度上进行了优化如下代码:intmain() inti=0; intarr[10]=0; for(i=0;i<=12;i++) arr[i]=0; printf("hehe\\n"); system( 查看详情
c语言初阶笔记程序员必须要会的实用调试技巧(含库函数strcpy和strlen的模拟实现)!!(代码片段)
目录 为什么要学习调试?什么是bug?调试是什么,有多重要?调试的概念及重要性调试的步骤Debug和Release的介绍windows环境调试介绍1.调试环境的准备2.学会快捷键F5F9F10F11CTRL+F53.调试的时候查看程序当前信息查看临... 查看详情
c语言学习--visualstudio基本调试方法(代码片段)
文章目录调试的基本步骤Debug和Releaserelease对代码的优化Windows环境调试调试环境准备断点调试设置断点开始调试条件断点逐过程调试逐语句调试跳出函数快速运行到光标处监视窗口调用监视窗口设置监视项自动窗口局部变量窗口... 查看详情
08实用调试技巧(代码片段)
到这一章节,C语言初阶的基础知识基本完结,那么我们已经具备了基础的代码编程能力,还需要在牛客,LeetCode,PTA,洛谷等平台刷题训练,或参加编程竞赛提高自己编程水平。今天,我们来谈谈... 查看详情
8个python加速运行的小技巧(代码片段)
Python是一种脚本语言,相比C/C++这样的编译语言,在效率和性能方面存在一些不足。但是,有很多时候,Python的效率并没有想象中的那么夸张。本文对一些Python代码加速运行的技巧进行整理。0.代码优化原则... 查看详情
8个python加速运行的小技巧(代码片段)
Python是一种脚本语言,相比C/C++这样的编译语言,在效率和性能方面存在一些不足。但是,有很多时候,Python的效率并没有想象中的那么夸张。本文对一些Python代码加速运行的技巧进行整理。0.代码优化原则... 查看详情
嵌入式linux小项目之图片编解码播放器(代码片段)
...织,每个东西丢到合理的位置可参考:《华为的C语言编程规范》链接地址:我用阿里云盘分享了「华为C语言规范.p 查看详情
20个chromedevtools调试技巧(代码片段)
译者按: ChromeDevTools很强大,甚至可以替代IDE了!原文: ArtofdebuggingwithChromeDevTools为了保证可读性,本文采用意译而非直译。另外,本文版权归原作者所有,翻译仅用于学习。谷歌开发者工具提供了一系列的功能来帮助开... 查看详情
c++primer-遍历小技巧(代码片段)
使用一下方法遍历较简单,且输出是占一行:for(autoc:scores)cout<<c<<"";比起下面简单得多,下面输出是一个数字一行:for(string::size_typei=0;i<;++i)cout<<scores[i]<<endl; 查看详情
github小技巧-定义项目语言(代码片段)
...端项目难免会包含前端的资源,有时候就会被标记成前端语言,因为项目里css等文件比较多,被误识别成css项目。GitHub不提供指定项目语言的功能,感觉挺傻的。不过可以通过忽略文件的方式来达到指定语言。这个项目中前端资... 查看详情
c语言有这个就够了七.实用调试技巧
(一)什么是BUG历史上第一个bug导致程序运行错误的对象(二)调试是什么调试就是破案的过程,因为有人写代码是这样的:1.调试又称除错,是发现和减少计算机程序或电子仪器设备中程序错误的一个过程。2.调试的基本步骤... 查看详情
lua-调试技巧(代码片段)
title:lua-调试技巧categories:Luatags:[lua,调试,技巧]date:2022-07-1416:31:27comments:falsemathjax:truetoc:truelua-调试技巧前篇游戏lua脚本调试技巧,达到修改逻辑脚本后能实时生效执行,提高开发效率pc端editor模式新建一个测试代码脚本gDebugCustom=gD... 查看详情
lua-调试技巧(代码片段)
title:lua-调试技巧categories:Luatags:[lua,调试,技巧]date:2022-07-1416:31:27comments:falsemathjax:truetoc:truelua-调试技巧前篇游戏lua脚本调试技巧,达到修改逻辑脚本后能实时生效执行,提高开发效率pc端editor模式新建一个测试代码脚本gDebugCustom=gD... 查看详情
lua-调试技巧(代码片段)
title:lua-调试技巧categories:Luatags:[lua,调试,技巧]date:2022-07-1416:31:27comments:falsemathjax:truetoc:truelua-调试技巧前篇游戏lua脚本调试技巧,达到修改逻辑脚本后能实时生效执行,提高开发效率pc端editor模式新建一个测试代码脚本gDebugCustom=gD... 查看详情
c语言初阶笔记程序员必须要会的实用调试技巧(含库函数strcpy和strlen的模拟实现)!!(代码片段)
目录 为什么要学习调试?什么是bug?调试是什么,有多重要?调试的概念及重要性调试的步骤Debug和Release的介绍windows环境调试介绍1.调试环境的准备2.学会快捷键F5F9F10F11CTRL+F53.调试的时候查看程序当前信息查看临... 查看详情
小技巧(代码片段)
按照a,b中每个字符串的第一个值,合并成c如下:a=[‘a,1‘,‘b,3,22‘,‘c,3,4‘,]b=[‘a,2‘,‘b,1‘,‘d,5‘,]c=[‘a,1,2‘,‘b,3,22,1‘,‘c,3,4‘,‘5‘]dic=dict([(i[0],i)foriina])print(dic)#组成元组形式,然后生成字典形式forvinb:ifdic.get(v[0]):dic[v[... 查看详情