C语言中程序调试和宏使用技巧

Linux·C语言高级编程·程序调试和宏使用的技巧 阅读详情
1)打印文件,函数和程序行   
     在linux使用GCC编译程序的时候,gcc在编译的过程中,会生成一些宏,可以使用这些宏分别打印当前源文件的信息。主要有当前文件(__FILE__,为字符串型char *),当前运行的函数(__FUNCTION__,为字符串型char *)和当前的程序行(__LINE__,为整型int)。使用实例如下:
printf("file:%s    function:%s    line:%d\n",__FILE__, __FUNCTON__, __LINE); 注意以上三个宏都是在编译的时候产生的宏,而不是变量。
2)#:字符串化操作符
     在gcc的编译系统中,可以使用#将当前的内容转换成字符串。例如:#define dprint(expr) printf("<main>%s=%d\n", #expr, expr);
int x= 100;
int y= 2;
dprint(x/y);              
结果如下:<main>x/y=50     这说明增加了#修饰之后的表达式,即代表了将宏中的参数名直接转换为字符串
进一步,看下面的调用:
dprint(/* printf variable information */x/y);
结果如下:<main>x/y=50   这说明编译器在生成字符串的时候,不会照搬宏参数中的所有内容,注释的内容是不会被放入字符串的宏,这也是因为去注释是编译器预处理阶段的内容,也就是说实际的编译过程之前,程序中注释已经去掉。
char* a="Test string"
dprint(a)    结果如下:<main>a=4206930   这是由于a不是整数,而是字符串的指针,因此打印出a的值是变量a的地址,而字符串的内容依然是a。再看:
int i=1234;
dprint(1234)     结果如下:<main>1234    这说明对于直接写入程序的数值(立即数),编译器也可以将它的内容转换为字符串。
上面的种种说明,那种方式的优点是可以通过统一的方法打印表达式的内容。同样可以定义如下的类似的宏,打印其它表达式的值:
#define printc(expr) printf("<char>%s = %c\n", #expr,expr);
#define printf(expr)  printf("<float>%s = %f\n", #expr,expr);
#define printd(expr) printf("<int 16>%s = %d\n", #expr,expr);
在gcc的编译器中,可以将两个字符串常量连接成一个新的字符串。如下方式表示的字符串是等价的:
“123456”与“123””456”
由于#expr本质就是一个字符串,因此程序中也可以不使用%s打印它的内容,而是可以将其直接和其它的字符串连接如下:
#define printc(expr) printf("<char>”#expr = "%c\n",expr);    其它的类似。
3)##:连接操作符

在GCC的编译系统中,##是C语言中的连接操作符,可以在编译的预处理阶段实现字符串的连接的操作。如下所示:

#define test(x) test##x
void test1(int a)
{
     printf(”Test1!\n“);   
}
void test2(int a)
{
     printf(”Test2!\n“);   
}

int main(void)
{
    test(1);
    test(2);
    return 0;
}
程序运行结果如下:
Test1
Test2
这说明test(1),这说明经过宏操作,由于##连接操作符,将test(1)变成了test1。
在程序的调试语句中,##常用的方式如下:
#define DPRINT(fmt,args…) printf(fmt, ##args)

4)调试宏的第一种方式如下:
#define DEBUG_OUT(fmt,args…)   \
{ \
     printf("File:%s    Function:%s    Line:%d\n",__FILE__, __FUNCTON__, __LINE__);   \
     printf(fmt, ##args);  \
}
在宏定义中,在每一行的结尾使用\表示下一行的内容是与上面连续的。经过这样处理的好处是可以在每行调试语句的前面打印出附加的信息,经过这样的宏处理后,DEBUG_OUT的方式和printf完全一致,可以支持可变参数列表和格式化输出,只是附加了一段当前文件,当前函数,当前行的信息。调用宏的方法,可以加语句结束的标志(;),这样像是函数调用,其实不是。这时的;表示程序多出来了一条空语句。如果不加的话, 也没错,宏调用本来就不加嘛,是吧?
但存在问题或者存在一些缺陷,实质是printf是一个有int返回值的函数,只是很少用而已。但根据DEBUG_OUT的定义,不可能再产生返回值,在绝大数的实际情况下 由于不用返回值,所以这还是挺常用的。
5)调试宏的第二种方式如下:
#define DEBUG_OUT(fmt,args…)  printf("File:%s    Function:%s    Line:%d"fmt, __FILE__, __FUNCTON__, __LINE__, ##args)
这个就解决了无法获得printf返回值的弊端。但同时却有另外一个弊端。这是由于printf函数的第一个参数是const char *格式,在使用的过程中,经常使用固定字符串表示格式输入参数。其实printf也可以使用变量作为第一个参数输入如下:
const char *s = "String";
printf(s);
以上格式是合法的,输出的结果就是s指向的字符串的值String。然而在上述DEBUG_OUT定义中,fmt必须是一个字符串,不能使用指针,只有这样才能实现字符串连接的功能。因此DEBUG_OUT(s)是不合法的。
6)使用一个变量USE_DEBUG然后用ifdef USE_DEBUG来开关控制调试宏。这样就不用在最终的发行版中为去掉调试宏而苦恼了。当然也可以USE_DEBUG定义一个值,当值不同时,根据实际情况使用不同的调试宏。
7)使用do…while的定义

使用宏定义可以将一些较为短小的功能封装,方便使用。宏的形式和函数类似,但是使用宏的话,就可以节省函数跳转的开销。在程序中常常使用do…while(0)来封装成一个宏。例如:
#define HELLO(str) do{\
printf("Hello:%s\n", str); \
}while(0)

c语言入门篇:程序调试方法 所谓程序调试是指对程序的查错和排错。 调试程序一般应经过以下几个步骤: 一、先进行人工检查,即静态检查。 在写好一个程序以后,不要匆匆忙忙上机,而应对程序进行人工检查。这一步十分重要,它能发现程序设计人员由于疏忽而造成的 多数错误。这一步往往容易被人忽视,总希望把一切都推给计算机去做,但这样会多占用机器时间,作为一个程序人员应当养成严谨的作风,每一步都要严格把关,不把问题留给后面的工序。 为了更有效地进行人工检查,所编的程序应力求做到以下几点: ①应当采用结构化程序方法编程,以增加可读性; 阅读详情

相关推荐

别再让地图加载慢吞吞!GeoServer + GeoWebCache 缓存配置实战(附性能对比)

本文详细介绍了如何通过GeoServer和GeoWebCache优化地图服务性能,实现地图加载速度的显著提升。从缓存机制解析到实战配置流程,再到高级性能调优技巧,帮助开发者构建高效地图缓存系统,解决地图加载慢的问题。

weixin_42525369的博客 407

嵌入式C语言程序调试和宏使用的技巧

2

qq_44885775的博客 548

从《视觉SLAM十四讲》到项目实战:一文读懂拓扑地图与语义地图为何是服务机器人的未来

本文探讨了服务机器人地图技术的演进,从传统几何地图到拓扑地图与语义地图的跨越。通过分析栅格地图的局限性和拓扑地图、语义地图的优势,揭示了它们在动态开放环境中的智能应用。文章还介绍了多模态语义融合架构和动态语义更新技术,为服务机器人的未来发展提供了技术路线图。

weixin_30292843的博客 478

用于调试的printf函数和自定义log函数

1. 用宏定义调试用的DPRINT #define DEBUG_ENABLE #ifdef DEBUG_ENABLE #define DPRINT(fmt, args...) fprintf(stderr, "[DPRINT...][%s %d] "fmt"\n", __FILE__, __LINE__, ##args); #else #define DPRINT(fmt, .

andylauren的专栏 2672

Transformer论文解读

Transformer有多牛逼不用多说,时隔7年我们再来看看论文原文,看看这篇深刻改变世界的文章都说了什么。当然逐字逐句解读已经意义不大,我们只列考点。

xian0710830114的专栏 4405

ubuntu emto-cpa安装与编译

ubuntu emto-cpa安装与编译

qq_45834835的博客 1436

巧用c语言宏定义实现自动注释调试代码,c语言预处理--宏定义

(个人笔记)宏定义对于用c语言编程的人是经常用,这里只讲使用中需注意的问题点和方便的用法。1.宏扩展中空格对扩展结果的影响#define a(y)a_expanded(y)a(x)被扩展为: a_expanded(x)#define a(y)a_expanded(y)a(x) 被扩展为: (y) a_expanded(y) (x)2.用宏实现自动注释调试代码假如用来打印trace的函数为trace...

weixin_31173113的博客 1018

ABAP Open SQL 数据拷贝导致 SAPSQL_DATA_LOSS:从报错机理到稳妥修复

数据类型与长度不合规。一旦在Open SQL的无损赋值检查里被发现,系统宁可中止也不会偷偷替你截断。把变量声明对齐到字典、在需要时明确表达转换/截断意图、写法上避免落入高危的操作数位置,再配合ATC的预防性检查,既能解决你这次的ST22Dump,也能把同类问题消灭在萌芽状态。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 428

18.3 #define DM9000_DBG(fmt,args...) printf(fmt, ##args)代表什么

标准C支持可变参数的函数,意味着函数的参数是不固定的,例如printf()函数的原型为:int printf( const char *format [, argument]... ) 而在GNU C中,宏也可以接受可变数目的参数,例如: #define DM9000_DBG(fmt,args...) printf(fmt, ##args) 这里args 表示其余的参数可以是零个或多个,这些...

weixin_30437847的博客 725

成功解决安装cuda的时候,下载的文件自动消失,并且出现An unknown error has occurred

成功解决安装cuda的时候,下载的文件自动消失,并且出现An unknown error has occurred. 目录 解决问题 解决思路 解决方法 解决问题 安装cuda的时候,下载的文件自动消失,并且出现An unknown error has occurred. 解决思路 发生未知错误。 解决方法 很可能是因为当前电脑下载的cuda版本不适合当前电脑GPU支持的cuda版本! 推荐文章:CV:Win1..

头部AI社区如有邀博主AI主题演讲请私信—心比天高,仗剑走天涯,保持热爱,奔赴向梦想!低调,专注,谦虚,自律,反思,成长,还算比较正能量的博主,公益免费传播…内心特别想在AI界做出一些可以推进历史进程影响力的技术(兴趣使然,有点小情怀,也有点使命感呀 7523

手把手教你学Simulink--基于Simulink的风力发电系统用双馈电机控制仿真建模

特点高效节能:在广泛的风速范围内保持高效的能量转换。独立控制有功和无功功率:通过控制转子电流实现对有功和无功功率的独立调节。较低的成本:相比直接驱动或全功率变流器方案,成本较低。挑战控制复杂度较高:需要复杂的控制算法来实现有功和无功功率的解耦控制。对电网波动敏感:需要良好的稳定性控制策略以应对电网电压波动。利用Simscape Electrical中的模块构建DFIG的物理模型,配置参数如电阻、电感、极对数等。matlab深色版本% 添加DFIG电机模块。

MHD0815的博客 347

【嵌入式】C语言程序调试和宏使用的技巧

00. 目录 文章目录00. 目录01. 调试相关的宏02. # 字符串化操作符03. ## 连接操作符04. 调试宏第一种形式05. 调试宏的第二种定义方式06. 对调试语句进行分级审查07. 条件编译调试语句08. 使用do...while的宏定义09. 代码剖析10. 附录 01. 调试相关的宏 在Linux使用gcc编译程序的时候,对于调试的语句还具有一些特殊的语法。gcc编译的过程中,会生成一些宏,可以使用这些宏分别打印当前源文件的信息,主要内容是当前的文件、当前运行的函数和当前的程序行。 具体宏

C/C++软件工程师、嵌入式软件工程师、物联网研发工程师、C/C++讲师、物联网讲师、嵌入式讲师、鸿蒙讲师---欢迎大家一起交流(私信添加博主微信) 4172

【WRF后处理】基于wrf-python处理wrf运行结果wrfout_d01

基于wrf-python处理wrf运行结果wrfout_d01

WW、forever的博客 5209

【嵌入式】C语言程序调试和宏使用的技巧(转载)

目录 文章目录 目录 调试相关的宏 字符串化操作符 连接操作符 调试宏第一种形式 调试宏的第二种定义方式 对调试语句进行分级审查 条件编译调试语句 使用do…while的宏定义 代码剖析 附录 调试相关的宏 在Linux使用gcc编译程序的时候,对于调试的语句还具有一些特殊的语法。gcc编译的过程中,会生成一些宏,可以使用这些宏分别打印当前源文件的信息,主要内容是当前的文件、当前运行的函数和当前的程序行。 具体宏如下: FILE 当前程序源文件 (char*) FUNCTION 当前运行的函.

forest_tree的博客 530

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

C基础-9

一、十大滤波算法一)、限幅滤波法1、方法:根据经验判断两次采样允许的最大偏差值(设为A)每次检测到新值时判断:a. 如果本次值与上次值之差<=A,则本次值有效b. 如果本次值与上次值之差>A,则本次值无效,放弃本次值,用上次值代替本次值2、优点:能有效克服因偶然因素引起的脉冲干扰3、缺点无法抑制那种周期性的干扰...

weixin_40320783的博客 99

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

c语言测试题1-6章,C语言1-6章填空题

if(i>=j-1) printf(\} }答案: 5359第6题 (1.0分) 题号:170一个用C语言编写的程序在运行时,如果没有发生任何异常情况,则只有在执行了【1】函数 的最后一条语句或该函数中的return语句后,程序才会终止运行. 答案: 主=========或========= main第13题 (1.0分) 题号:533变量从存储的时间来分可分为【1】和动态变量.第1...

weixin_35896668的博客 2031

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

C语言之顺序结构以及程序调试的debug宏

C语言中顺序结构和程序调试的debug宏

tmk1234567890的博客 1350

C语言程序调试常用方法与技巧

本文介绍了C语言程序调试的常用方法与技巧。主要内容包括:调试的基本概念和步骤,GCC编译器和GDB调试器的安装配置,GDB的断点设置、单步调试、变量查看等基本使用方法,以及缩小错误范围、使用打印语句、断言分析等实用调试技巧。文章还列举了语法错误、语义错误和运行时错误等常见错误类型及其调试方法。通过掌握这些调试工具和技巧,可以有效提高程序调试的效率和准确性,确保程序的正确性和可靠性。

编程世界如山海,探索不止。 1万+

C语言之预处理和宏

在调用宏时,首先会对传入的参数进行检查,查看参数中是否包含其他由 #define 定义的符号。例如,若已定义 #define PI 3.14 , #define R 2 ,又有宏 #define CIRCUMFERENCE 2 * PI * R ,在使用 CIRCUMFERENCE 时, PI 和 R 会先被替换成 3.14 和 2。完成参数中符号的替换后,预处理器会将宏定义中的替换文本插入到程序中调用宏的原始位置,此时宏定义中的参数名会被传入的实际参数值所替换。

2401_87353862的博客 839

c语言程序调试中的单步调试,c语言调试技巧总结

c语言调试技巧总结2007-12-31 20:38:19|分类: 编程资料 |标签:|字号大中小经过这么多程序的编辑与调试,需要总结一些经验,以免在以后的调试中乃中当初无知的起点出发开始摸索!在整个程序编辑完毕并通过编译后,对各个函数进行调试.首先用一组简单的数据对程序进行调试,是否各函数有出错现象.然后用复杂数据对程序进行调试.直到确定程序对正常数据没有错误为止.第二,当数据测试时,程序...

weixin_42627812的博客 1484

调试技巧MFC中TRACE宏的使用

个人总结:最近看网络编程是碰到了TRACE语句,不知道在哪里输出,查了一晚上资料也没找出来,今天终于在优快云上找到了,真是个高地方啊,方法如下: 1.在MFC中加入TRACE语句 2.在TOOLS->MFC TRACER中选择 “ENABLE TRACING”点击OK 3.进行调试运行,GO(F5)(特别注意:不是执行‘!’以前之所以不能看到TRACE内容,是因为不是调试执行,而是‘!’了

ghevinn欢迎您光临 1万+

kiel实现c语言编程,Kiel 软件的使用和简单C程序调试

《Kiel 软件的使用和简单C程序调试》由会员分享,可在线阅读,更多相关《Kiel 软件的使用和简单C程序调试(15页珍藏版)》请在人人文库网上搜索。1、单片机原理与接口技术实验 实验一:Kiel 软件的使用和简单C程序调试 一、实验目的: 1、通过实验学会用C语言进行简单程序的设计。 2、学会应用keil-uvision集成调试软件对C语言程序进行调试。掌握C语言程序的编辑、编译、运行、单步调试...

weixin_36125719的博客 935

【C语言调试高手进阶】:掌握assert宏的5大核心技巧与实战应用场景

掌握C语言断言assert宏调试用法,快速定位程序逻辑错误。详解5大核心技巧,涵盖参数验证、内存检测等实战场景,提升代码健壮性与调试效率,适用于开发与测试阶段,值得收藏。

LiteTrans的博客 1087
上一篇: 算法解析之大数乘法
下一篇: 频繁关联规则挖掘之FP树
wustdatamining
博客等级 码龄15年 12粉丝 81原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值