C语言系列文章之#和##

很久就知道了 # 和 ## ,但是都没怎么使用,直到最近的项目涉及到需要编写大量相似的代码之后才决定尝试使用 ## 去简化代码的书写。

比如说我的项目需要控制四个通道的电机,四个通道的逻辑控制代码都是类似的,只是对应的硬件和数据信息不同而已。而我是一个讨厌做重复工作的人,所以就想利用 ## 去简化我的代码书写。

就比如说代码初始化这一块,总共有四份相似的代码,如果每一个都要去源码的位置进行修改,麻烦不说,还有可能忘记修改某部分代码,导致程序的bug。对此比较好的方式就是使用宏定义,将所有需要修改的东西整合在一个位置,这样进行修改的时候就能一次性修改完成,就不用在源码中到处找哪里需要修改了。而为了更好的配合这种修改方式,使用 ## 就很有必要了。

下面看看在我项目中的应用吧!

以两个通道为例:

.c文件

640?wx_fmt=png

.h文件

640?wx_fmt=png

使用 ## 的宏定义

640?wx_fmt=png

当我需要初始化新的通道的时候,在源码位置只要修改一个地方就行就行,而头文件部分的修改不管采用哪种方式都是必不可少的,这没什么好说的。而当采用 ## 的方式编写代码,你后期如果需要增加一个通道的初始化代码,你的工作就是复制前面通道的代码,然后修改源代码的那一个宏定义,最后在头文件中统一修改引脚信息就行了。

而实现这种方式的关键就是 ##,它的作用就是将你写的标志符进行拼接,相当于自动实现代码的编写了。

上面那么多话如果没有实际使用经验其实不是特别好理解,现在以比较简单的方式进行说明。

在对引脚进行初始化的时候,一般需要端口信息、引脚信息(当然还需要对应的时钟信息,暂时不考虑)

使用库函数进行开发时一般是采用以下方式进行引脚初始化:

640?wx_fmt=png

只有单个引脚的时候,只要修改这两个地方就能实现一个引脚的初始化,还是比较简单的。但是如果有多个相同模式的引脚需要进行这样的初始化,就会显得很麻烦。而且一旦硬件修改了,就可能会有很多地方需要修改,很可能就忘记某个地方的修改了。所以为了方便的对需要修改的地方进行修改,就很有必要使用一个标志符去代替具体的信息。所以一般就会采用宏定义的方式:

640?wx_fmt=png

这样一旦后期要改了,因为已经将所有要修改的地方都放在一块了,那么即使过去了很久,也能很快的根据硬件开发板进行修改。而不会说忘记修改哪部分代码了。

但这是比较常规的写法,在没大量相似代码的情况下还是很方便的,但是如果说我有两、三个SPI_MISO引脚呢?我怎样才能更快的写出我的代码呢?就是使用 ## 进行拼接了。

首先你要确定你变化的是什么,不变的又是什么。变化的就是不同的引脚,不变的就是都是开漏复用输出等配置。

现在看看如何实现。

首先看看常规的操作:

640?wx_fmt=png

当修改完这两个地方时,第二个SPI的引脚就算是配置完成了。但是万一你忘记修改了一个地方呢?所以,现在想办法只修改一个地方,从而达到修改两个地方的目的(多个地方修改也是同理)。

640?wx_fmt=png

这就是 ## 的好处了。

现在讲讲如何正确使用 ##。

和宏定义一样,遇到相同字符就会被替换,比如:

640?wx_fmt=png

这里有两个spix,所以两个都被替换了成了1,然后通过 ## 进行拼接。这个可以通过编译看出来最终拼出来的是什么(在拼出问题的情况下才能看到。当然你也可以直接让鼠标指针选择被拼接的地方也能看出来,这样就不用进行编译了)。

640?wx_fmt=png

如果说你传入的参数不是 1,而是一个宏定义(就像SPIx是一个宏定义),那么你就需要加一个外壳进行二次替换才行。

640?wx_fmt=png

很多时候我们要求被替换的东西加入一对括号 (),但使用 ## 进行拼接的时候却最好不要,否则可能拼接失败(如果拼接失败,看看是否是因为这个):

640?wx_fmt=png

如果有多个变化的地方,那么宏中传入多个参数就可以了,类似这样的:

640?wx_fmt=png

如果拼接失败,请先确保你传入的参数是 MISO,而不是 MOSI:

640?wx_fmt=png

以上是比较常用的使用方式,但有时候我们真的很懒,两个没有直接联系但有间接联系的参数我也想通过某种方式进行拼接:

640?wx_fmt=png

可以看到,在其他宏没有改变的情况下,虽然我传入的参数是Sx为4,4可以说和最终的拼接 SPI1_MISO_GPIO_Pin_x 没有任何关系,但是通过再次拼接参数宏的方式硬是让最后的拼接结果变成了 SPI1_MISO_GPIO_Pin_x。

现在简单分析一下拼接的过程:

首先编译器碰到了 SIPx(Sx),然后 Sx是 4,通过中间转换宏:

#define SPIx(x)                           _SPIx(x)

                                            

变成了 _SPI(4),然后通过宏:

#define _SPIx(x)                           SPI##x##_MISO

拼接成了 SPI4_MISO,也就是:

SPIx_MISO_GPIO_Pin_x(SPI4_MISO)

因为SPI4_MISO也是一个宏,所以继续通过转换宏:

#define SPIx_MISO_GPIO_Pin_x(spix)       _SPIx_MISO_GPIO_Pin_x(spix)

在这里 SPI4_MISO 被替换成了 1,也就变成了这个:

_SPIx_MISO_GPIO_Pin_x(1)

但还没完,继续替换,通过下面的宏:

#define _SPIx_MISO_GPIO_Pin_x(spix)     SPI##spix##_MISO_GPIO_Pin_x

拼接为:

SPI1_MISO_GPIO_Pin_x

但是它还是一个宏,所以 SPI1_MISO_GPIO_Pin_x继续被替换为:

GPIO_Pin_4

这就算替换完了吗?非也,实际上 GPIO_Pin_4 也是一个宏:

640?wx_fmt=png

所以继续替换,最终替换成了:

((uint16_t)0x0010)

是不是感觉好麻烦啊,为了一个 ((uint16_t)0x0010) 不知道走了多少弯路,不过总算是替换完了。你一个新手确实觉得难,但理解之后也就不难了。而高手写代码时写这么多的宏,不会觉得累吗?其实不是的,相比于不写宏造成的后果,还是写宏来的简单一些,高手经历的更多,当然也就考虑的更多,他们既然选择写宏,就有他们的道理,等新手有足够的经验之后,也就明白了写宏的用意,也就乐意写宏了。

以上就是我使用 ## 时遇到的一些问题。要理解 ## 其实不难,多想多尝试就可以了。现在你从头开始看看吧,或许会有不一样的理解。

现在讲讲 #。这个比较简单一点,鱼鹰也没怎么用过,就简单介绍一下吧。

1、 使用 # 让传入的宏参数变成一个字符串:

#define  STRING(x)    #x

则STRING (1+1)  相当于  “1+1”,即把 1+1 变成了可以放在数组中的数据了。

2、 使用 #@ ,让参数变成字符

#define CHAR(x)     #@x

则CHAR (a) 即‘a’,B(1)即’1’这就变成了可以把它放入变量中的字符了。但B(abc)

却不甚有效。这是因为 abc不是一个字符。

-----------------2018/12/16 Osprey

640?wx_fmt=png

看以上示例,包含 ## 的宏既可以传入字符,也可以传入你需要的参数。可以根据你的需要设计所需的宏。       

----------更新 2019/01/07 Osprey

640?wx_fmt=png

640?wx_fmt=jpeg

扫码或长按关注

回复「 加群 」进入技术群聊

   

640?wx_fmt=gif

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/468275.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

springboot 上传文件_基于SpringBoot的文件上传

在实际的企业开发中,文件上传是最常见的功能之一,SpringBoot集成了SpringMVC常用的功能,当然也包含了文件上传的功能,实现起来没有太多的区别。下面我们来讲解一下,使用SpringBoot如何实现多个文件上传操作。使用的环境…

Linux的 i2c 驱动框架分析

1.基本概念总线设备驱动模型,是Linux 内核的一个基础,基本理论可以说按照大企业的分工原则,每个人只要负责自己的事情,向其他部门给出标准的接口调用,后勤部就负责后勤工作,厨房有可能跟后勤部产生工作上的…

matlab fftshift_数字信号处理没有Matlab?用Python一样很爽

通常,在数字信号处理时,我们避不开matlab这个工具,因其它的强大的功能受到广大工程师的好评,也一直都是业界的不二之选。但是,matlab毕竟是商业软件,公司里如果使用的话,就需要支付高昂的费用。…

栈,C语言实现

什么是数据结构?数据结构是什么?要了解数据结构,我们要先明白数据和结构,数据就是一些int char 这样的变量,这些就是数据,如果你是一个篮球爱好者,那么你的球鞋就是你的数据,结构就是…

Camera摄像头工作原理

回想这工作的这几年,尝尽社会的辛酸艰难,从一开始什么都没有到30万,从30万到200万,从200万到1300万,不是炫耀,我只是想通过我自己的经历告诉我的朋友们「手机像素越高,拍的照片越清晰」摄像头结…

es6一维数组转二维数组_技术图文:Numpy 一维数组 VS. Pandas Series

背景Numpy 提供的最重要的数据结构是 ndarray,它是 Python 中 list 的扩展。Pandas 提供了两种非常重要的数据结构 Series和DataFrame。Numpy 中的一维数组与 Series 相似,一维数组只是提供了从0开始与位置有关的索引,而Series除了位置索引之…

unity UI事件

由于工作需要到持续按键,所以了解了一下unity UI事件,本文主要转载于http://www.cnblogs.com/zou90512/p/3995932.html?utm_sourcetuicool&utm_mediumreferral,并对相关问题进行解释。 我们最常用到的就是unity的button组件,…

电子工程学院的师兄弟姐们们,老师叫你们回家

昨天写了很长的文章,接收到推送的同学们应该也会很开心,但是由于我的原因,需要把文章删除「你们能想到的原因肯定不是我删文的原因」,但是呢,也因为这样,又可以重写一篇,刚好可以多加点内容。后…

auto.js停止所有线程_Java多线程编程基础知识 概念介绍,以及线程状态

一、进程进程是操作系统结构的基础;是一次程序的执行;是一个程序及其数据在处理机上顺序执行时所发生的活动。操作系统中,几乎所有运行中的任务对应一条进程(Process)。一个程序进入内存运行,即变成一个进程。进程是处于运行过程中…

Linux 进程管理数据结构

文末集赞留言抽奖,我会选出留言点赞数前 3 名送出小米耳机。别刷赞啊,刷赞被举报无效,相信真的是公众号粉丝的读者,不会做这样的行为,刷赞指的是购买外挂刷,如果是转发到朋友圈和微信群的,不算刷…

如何安装python3.8_python3.8下载及安装步骤详解

1.操作系统:Windows7 64bit executable installer 2.安装步骤: 双击安装文件python-3.8.0-amd64.exe 勾选下方“Add Python 3.8 to PATH”,并选择“Customize installation”3.把Optional Features全部勾选上,点击“Next"4.A…

队列,C语言实现

什么是队列?上一篇文章写了什么是栈,用C语言实现了栈,既然说了栈,不说队列,感觉总是少了点什么,所以就顺手写一个队列,而且最近做项目也用到这个队列的代码。栈的特点是先进后出,队列…

华为hr,我尽力了

最近,一则新闻很火但是突然,又不火了,火于不火之间,时间有点短,其中猜测很大部分是gongguan原因以下为正文截图~以上为事件原文,这个是一个热点新闻,之前发了一个热点新闻,瞬间就火爆…

idea,eclipse创建多模块项目

新建一个maven项目 iead,新建是不选择archetype,新建好之后,pom中的 <packaging>pom</packaging>节点是默认的,如果不是要改成这这样子 然后选中这个项目,新建一个module,之后就和建立普通项目一样了. eclipse 是这样的 建一个普通的maven项目就可以了 这个是建好之…

python画图程序代码_少儿python编程(7)海龟画图(拓展1)

我们继续用Python的海龟库来画图吧&#xff01;上图是画一朵花的程序&#xff0c;重点是6-12行&#xff0c;使用了函数来定义drawleaf:每一掰叶子由两条弧线组成&#xff0c;每一条弧线重复画15次&#xff0c;每次前进5步&#xff0c;右转6度。看图形化代码就很清楚了&#xff…

opencv matlab三维点云,点云采样的三种方法 - 小白学视觉的个人空间 - OSCHINA - 中文开源技术交流社区...

点击上方“小白学视觉”&#xff0c;选择“星标”公众号重磅干货&#xff0c;第一时间送达编辑&#xff1a;3D视觉工坊本文由知乎作者GeometryHub授权转载&#xff0c;不得擅自二次转载。原文链接&#xff1a;https://zhuanlan.zhihu.com/p/86044055点云采样分类点云采样的方法…

C语言数组越界导致无限循环

大奖也是你们的&#xff0c;感谢支持&#xff0c;不喜欢的请轻拍。过年抽奖我还是很期待的&#xff0c;每年公司的年会抽奖的时候&#xff0c;我总是能小中一把&#xff0c;有一年我还中了个一等奖&#xff0c;不知道大家对一等奖什么概念&#xff0c;中一等奖的概率非常低&…

七月流水账

7.1-7.3 >< 7.4 看了一会儿李老大给的Caffe的教程 重配python qt vtk&#xff0c;大概是原来装了一个xxx&#xff08;忘记名字&#xff09;&#xff0c;然后位数有些不对&#xff0c;搞了好一阵 果然还是卸载重装好>< 然后又看了会儿Matlab神经网络工具箱怎么用 …

python绘制拟合回归散点图_机器学习之利用Python进行简单线性回归分析

前言&#xff1a;在利用机器学习方法进行数据分析时经常要了解变量的相关性&#xff0c;有时还需要对变量进行回归分析。本文首先对人工智能/机器学习/深度学习、相关分析/因果分析/回归分析等易混淆的概念进行区分&#xff0c;最后结合案例介绍如何利用Python进行简单线性回归…

十年经验教你如何学习嵌入式系统

一、如何学习嵌入式系统- - 嵌入式系统的概念着重理解“嵌入”的概念 &#xff0c;主要从三个方面上来理解。1、从硬件上&#xff0c;“嵌入”将基于CPU的处围器件&#xff0c;整合到CPU芯片内部&#xff0c;比如早期基于X86体系结构下的计算机&#xff0c;CPU只是有运算器和累…