在使用了大量的宏来快速构建函数后,一个问题出现了:如果你发现某个地方出了bug,你得定位它,于是使用debugger,然而宏的“简易”导致你进行了许多次“下一步”还是停留在使用宏的那一行。
当然也不是完全没办法,如果你曾经接触过Python语言,并且听说过“Python语言八荣八耻”,那么你应该对这句话有印象——以打印日志为荣,以单步跟踪为耻。虽然我不太明白为什么Python语言有这样的论调,不过至少在使用宏的时候,这一点是非常值得借鉴的。废话少说,先来个实现:
#define shift(current, encounter, target) \
static void linkName(current, encounter)(struct LRAnalyser* self, \
struct Token* t) \
{ \
self->stateStack->push(self->stateStack, jerryLRStates + target); \
printf(#current \
" encouters " \
#encounter \
" shift to " \
#target \
"\n"); \
} /*******************************************************************/
这里展示的是在原来的宏shift内部增加一个输出语句,输出当前状态名、遭遇的符号类型、目标状态名。有了这些信息,LR分析器每一次移进你都不会错过——记得在那几个特殊的移进函数中也插入类似代码。如果有需要,也可以插入其他输出函数,把它们都塞进宏内部。不过注意版式,或者输出到特定的文件以保护视力。
说到跟踪调试和打印日志,围绕这个话题有很多争论。单步跟踪直观,而且不会破坏程序的执行,但是如果有一个很长的循环,比如循环1000次(这还不算很长吧),其中某些情况下会有故障发生,那么跟踪这个循环会让人厌倦于“下一步”和观察变量值;另一方面,一个printf更适合对付那些循环,但是在递归迭代过程中它就显得力不从心了——或者应该说观察输出的程序员往往很难确定到底哪个输出对应于哪一次递归调用——此外安插在代码中间的这些探针在不再需要时,清除它们也是一件很麻烦的事情,也许一不小心把需要的代码也给顺手牵羊了。两种方法应该互补,在恰当的情况下使用;或者,使用你认为可以解决问题的方法。
最后再说说宏。在C语言程序开发过程中,宏大部分情况下是用来伪装一个函数或常数,如EOF以及可变参数函数中用到的va_arg宏,此外还有一些经典的宏用来包装一个函数(可以认为这是Decorator模式的始祖),如assert宏。不过,像LR分析表实现过程中这样用来大段大段生成函数的宏并不多见。可以认为这是一种C语言风格的原始泛型编程,甚至于是一种编译时多态:每个函数都是一个对象,它们之间的差异仅体现在函数名和target成员,而每次调用宏时就如同调用构造函数一样。不过,它们的缺陷是,它们总会在内存中驻留,占用很多空间。
分享到:
相关推荐
在VB6(Visual Basic 6)环境中,开发Excel自定义函数加载宏是一项常见的任务,它允许程序员扩展Excel的功能,提供自定义的计算公式。通过创建动态链接库(DLL),我们可以编写VBA(Visual Basic for Applications)...
在C51编程环境中,精确延时函数的编写和调试是一项关键技能,特别是在单片机应用中需要精细时间控制的场合...在调试过程中,使用逻辑分析仪或示波器等硬件工具,可以帮助验证延时函数的实际效果,确保满足系统的需求。
这份"MTK常用函数及宏定义.zip_mtk 资料"是针对MTK平台开发人员的重要参考资料,尤其在UI(用户界面)层的绘制过程中非常实用。 在MTK平台上进行UI开发时,理解和掌握特定的函数以及宏定义至关重要。这些函数和宏...
本文详细探讨了基于C语言软件开发在提高开发效率、软件移植及调试方面的一系列技术和方法。以下为知识点的详细说明: 1. C语言软件开发效率提升方法: - 增量减量操作运算符:在C语言中,++和--运算符分别用于变量...
- **功能**:此宏用于调用UG API函数,并自动记录调用的位置及返回值。 - **实现细节**: - `report`函数负责实际的日志记录工作。 - `UF_CALL`宏会传递当前文件名、行号、被调用的UG API函数名称以及函数返回值...
在开发过程中,还需要注意到CAA框架对函数的特殊要求,比如函数声明中可能需要添加特定的宏定义,以及对于函数参数和返回值的类型要求。 在进行CAA二次开发时,还需要掌握一些其他关键知识点,例如如何通过CAA提供...
宏定义在代码开发和调试过程中扮演着重要角色,尤其在大型项目中,能够有效地提升效率和代码可读性。本文将深入探讨如何巧用C语言的宏定义来实现自动注释调试代码,帮助开发者更好地理解和应用这一技巧。 首先,...
在开发过程中,**ProToolkit.h**是最重要的头文件之一。为了确保异步模式下程序的正确运行,它必须是每个源文件中第一个被包含的PTK头文件。这是因为`pro_wchar_t.h`文件被`ProToolkit.h`所包含,而这个文件确保了`...
MTK调试过程详解 在移动设备开发中,尤其是基于MediaTek (MTK)平台的开发,调试是一项至关重要的任务,它对于新功能的研发、错误修复和算法研究具有决定性的作用。MTK的调试通常分为仿真调试和手机调试两种方式,每...
在嵌入式开发领域,STM32是一款广泛应用的微...总之,这个STM32调试信息打印函数是开发过程中的得力助手,它帮助开发者快速定位问题,理解程序运行状态,并且可以根据实际需求进行定制和优化,提高开发效率和产品质量。
这个过程中,编译器会检查语法错误和类型匹配,链接器则负责解决地址分配和函数调用等问题。 六、连接器 连接器是将多个编译单元(如.c和.asm文件)合并成单一可执行文件的关键工具。它负责解决符号引用、内存布局...
在C语言编程中,调试是开发过程中的重要环节,它能帮助我们找出代码中的错误,提高软件质量。"c语言调试宏"这个主题涉及到的是如何使用预处理器宏来辅助调试C程序。预处理器宏在编译阶段进行替换,可以在不改变原始...
宏定义适用于简单的代码替换,而内联函数适用于需要类型检查和调试的场景。 在选择使用宏定义还是内联函数时,应根据具体的需求和场景进行选择。如果需要简化代码并提高执行效率,可以选择宏定义;如果需要类型检查...
在实际开发中,我们应根据具体需求来选择使用宏还是内联函数。对于需要性能提升且代码简单的函数,可以考虑使用内联函数;而对于需要文本替换或简单计算的情况,宏可能是更合适的选择。同时,要谨慎使用宏,避免引入...
《SolidWorks二次开发API函数大全》是一份极为重要的参考资料,对于任何希望深入理解和利用SolidWorks进行定制化开发的工程师来说,都是不可或缺的宝典。SolidWorks是一款强大的三维机械设计软件,其二次开发功能...
7. **宏和脚本函数**:编写宏和脚本,自动化重复任务,提高效率。 在实际开发中,开发者需要结合UG的开发环境(如UGOpen API)和"ugopen_帮助函数.chm"文件,理解每个函数的用途和用法,通过编写UFUN脚本实现特定...
总结来说,函数插桩是软件开发中的重要工具,它允许开发者在不修改原始代码的情况下,增强程序的功能,进行深入的分析和调试。在Linux环境下,开发者可以根据实际需求选择合适的插桩阶段和方法,灵活地实现插桩功能...
宏帮助文档通常包含了大量的函数、命令和过程的解释,有助于用户理解和编写宏代码。 Excel 4.0宏是基于Visual Basic for Applications (VBA) 的早期版本,尽管现代Excel版本已经升级到VBA 7.x,但理解Excel 4.0宏...
**TRACE宏**是Microsoft Visual C++(简称VC)中用于输出调试信息的一种手段,主要用于帮助开发者在开发过程中跟踪和理解程序的运行状态。TRACE宏的一个显著特点是它只在**Debug**模式下生效,在**Release**模式下则...
如果在编辑过程中发现成员变量或函数的提示功能失效,可能是因为工程的导航数据库(.ncb文件)损坏。解决方法是: 1. 关闭项目; 2. 删除工程目录下的`.ncb`文件; 3. 重新打开项目,此时代码提示功能应恢复正常。 ...