如何有趣地进行C编程 ——记一次宏使用技巧
导语
自换城市生活后,我很久没有正儿八经地写一个技术类的博客和总结之类的了。我在南京时总是有相当多的事项想记录整理成文下来,但是却没有这么多的时间,毕竟逐项验证和整理是很费时间的,而我的时间一直都不算多。
回到武汉后,我开始从各种方面开始思考我的生活和我的职业:我到底想要什么样的生活,我到底该如何发展我的技术才能让自己快乐,以及那个终极问题,什么是有意义的人生。
我之前的工作一直是在驱动层面修修补补,如何把硬件全部的性能体现出来,如何提高换算速度、兼容性和可移植性是我的工作意义。我总是没有做出一个完整且满意的玩意,以至于我在武汉找工作时,首选就是做应用而非驱动。也算是有些改变吧。
之前我总在关注电路,接口和驱动,现在慢慢地开始拓展到一些其他的方面。
宏在C编程中的使用
宏是什么?
在C语言的编程中,我们首先写出一个一个的.c源文件,在单片机编程中有时会有一个用汇编语言写的.s的启动源文件,然后keil的ARM CC、IAR的编译器或者我现在用的最多的GCC的工具链将各个源文件编译成一个个的.o对象文件,最后由各自的链接器根据各自的链接规则将对象文件里的元素集合生成一个可执行文件。
按照《编译原理》的介绍和最初学C语言带来的印象,C语言的C文件是需要先通过编译器生成汇编文件,再通过汇编器生成机器指令,但是实际上在GCC中貌似是由C文件直接生成二进制指令的.o文件的,跳过生成汇编文件这一步。在ARM CC中,还有生成.txt文件的选项,可以看到各个.c的源码和汇编语句对照,很方便。在程序跑飞等情况发生时,我还是根据之前调试RISC-V代码保留的习惯,立刻使用反汇编工具生成机器码和源码对照文件,根据硬件错误中断中汇报的地址分析程序跑飞的原因。这里GCC的优势就很让人舒服:他的反汇编工具可以直接生成已经链接好的文件,而不是ARM CC中那样分立的文件。
链接是一个很重要的步骤,链接器将各个对象文件里的元素集合整理,最终根据脚本或者其他的方式决定各个代码段、带初值的变量和常量在flash中的存放位置,并决定哪些全变量存在内存哪里,堆和栈如何分配,最终它生成了工程文件,并提供了map文件告诉我们具体的空间占用和分配位置。
那么,宏是什么?为什么要使用宏?
在源文件进行编程之前,实现进行预编译这个步骤,预编译这里最重要的步骤就是进行源文件的文本处理。C语言的预编译命令是以#开头的,比如常见的#include 是将后面文件名的文件里的语句全部复制到这个位置,#if /#ifdef/#ifndef是有条件的编译,#error是用户自定义报警等等。 #include一般是包含头文件,但是我经常也能见到包含.c文件的骚操作,这时一般是要将被包含的.c文件排除在工程之外。
可见宏命令主要是为了辅助编码的工作,主要是进行文本操作,本次讨论的技巧内容关乎这几个宏命令,#define,#undef,##,#这么四个。
我们的目标主要是这几个:节省编码时间,使代码简介规范。
XMICRO的使用
预定义
在我们需要处理某些有共同属性需要关注的大量元素时,可以使用XMICRO来辅助编程吗,定义一些常变量和函数。首先我们使用#define来统一对元素进行预定义,如下:
#define guanggu_de_loupan
xmicro(guanggudonglu, 14500, 103)
xmicro(shilixinghe, 12500, 106)
xmicro(guocaigongyu, 13000, 14)
xmicro(gaungguxingcheng, 16000, 43)
xmicro(qushuixiyuan, 23000, 14)
这里我们关注的是光谷的楼盘这类事物,每个元素关注三个属性,分别是名称字符串,单价和距离管委会的直线距离,这里列举了guanggudonglu,shilixinghe,guocaigongyu,gaungguxingcheng和qushuixiyuan这五个楼盘。这里使用了\作为指示下段同行符号,需要注意的是,这个guanggu_de_loupan仅仅是一个宏定义,它怎么使用是后面的事情,单独出现并不会有什么影响。
定义
在实际使用的时候,可以根据自己的需要来进行选择实现数据类型定义,常量定义,变量定义,函数定义。由#define和#undef配合完成定义的实现。如:
枚举类型定义:
typedef enum
{
#define xmicro(A,B,C) enum_##A,
guanggu_de_loupan
#undef xmicro
}enum_guanggu_de_loupan;
预编译后为:
typedef enum
{
enum_guanggudonglu,
enum_ shilixinghe,
enum_ guocaigongyu,
enum_ gaungguxingcheng,
enum_ qushuixiyuan,
}enum_guanggu_de_loupan;
结构体类型定义:
typedef struct
{
#define xmicro(A,B,C) unsigned int A,
guanggu_de_loupan
#undef xmicro
} guanggu_de_loupan_t;
后记
这篇博文在我的桌面上躺了非常久,以至于我都忘记当时的行文构思了。直到24年五一之后我把它推上来。我除了列举的作用中,也用其批量来实现函数过。