C语言宏定义使用分析

 更新时间:2020年4月25日 17:48  点击:1538

1、如何区分宏定义中的“宏名称”和“宏字符串”?对于带参数的宏又该注意什么?

在宏定义中,“宏名称”和“宏字符串”是通过“空格”来区分的。编译器在处理时宏定义时,首先从“#define”后第一个空格开始读取字符串,直到遇见下一个空格为止,两个空格之间的字符串为“宏名称”,确定好“宏名称”之后,本行的所有其他字符串都为“宏字符串”。图示:#define + N个空格(1 < N) + 宏名称(中间没有空格) + N个空格(1 < N) + 宏字符串(直到本行结束)。这里讲到的都是一行之内的宏定义,如果跨越多行则用“\”字符进行“续行”,本质上可以当做一行来对待。

对于“带参数宏”,宏名称和“( )”之间不能有空格,否则就变成了“无参数宏”(根据上面的原则)。而且当“无参数宏”和“带参数宏”的名字相同时,“无参数宏”会屏蔽掉“带参数宏”,即使以“带参数宏”的方式调用,也行不通。

试验内容及结果

实验分析

可以看到“#define PI  3.1415”和“#define P I 689”分别是两个不同的宏定义“PI”和“P”;"G(4)"被“(X) (2*X) (4)”替换掉;当调用“F(4)”时,系统并没有替换成“2*4”,而是替换成了“123(4)”,说明“#define F  123”完全屏蔽掉了“#define F(X)  (2*X)”,当注释掉“#define  F  123”后"#define F(X)  (2*X)"可以正常工作。因此,在进行宏定义时,要密切关注空格的影响,并且“带参数宏”和“无参数宏”的名称一定不能相同,否则会出现混乱。但是,在宏调用时空格并不影响效果,例如F(3)和F (3)效果相同(F(X)是带参数宏)。

2、宏和函数在使用方式和效果上有何异同?

在宏定义时,要善于利用括号对变量进行封装,把每个参数都括起来,预防出现与优先级有关的问题;同时整个结果表达式也应该括起来,以防止当宏用于一个更复杂的表达式时可能出现问题。尽量提高宏的可靠性,。例如:“#define ABS(x)  (((x) > 0) ? (x) : (-x))”的可靠性要远远优于“#define ABS(x)  x > 0 ? x : -x”,可以以ABS(a-b)来进行试验。

在宏调用时,如果有自增(++)或自减(--)操作符,一定要注意很可能会产生副作用。因为宏在替换时,如果变量出现了多次,就相当于自增或自减操作进了多次,这个跟函数调用是完全不同的,函数调用中形参会复制实参的数值,并对形参进行操作并不会影响实参,而宏调用就是直接多次修改实参。例如:a = 5; "ABS(a++) “展开后就变成“(((a++) > 0) ? (a++) : (-a++))”,操作完成后”a = 7“而不是”a = 6“;当写成函数就完全不用担心这个问题。

如果在宏调用时,进行了了多层嵌套调用,则宏展开后会产生非常庞大的表达式,而且相当复杂;函数调用则不会出现这种情况。

3、宏和类型定义typedef的区别

由于宏的本质就是替换,所以可以对变量类型进行一层封装,利用该封装做变量定义,这样做的好处是增加可移植性,当修改时只需要改动宏定义即可。例如:

复制代码 代码如下:

MY_TYPE a;
MY_TYPE b,c,d;

但是最好不要这么用,因为我们有typedef,它是专门进行类型定义的。而且,使用类型定义会使代码更加通用一些,避免一些深层的问题。例如:
复制代码 代码如下:

typedef uint_8 * MY_TYPE2

MY_TYPE1 a,b;
MY_TYPE2 c,d;
分析

从概念上看,MY_TYPE1 和 MY_TYPE2 完全相同,都是指向uint_8的指针,但是当我们声明多个变量时,就出现问题了。它们分别被扩展成了:

复制代码 代码如下:

uint_8 *a,b;
MY_TYPE2 c,d; //因为MY_TYPE2已经是一种类型了

可以看到,本来想定义两个指针变量a,b;现在却变成了一个指针变量a和一个整型变量b,这不是我们想要的。而MY_TYPE2本身就是一种类型(自定义)了,故c,d都是指针类型,符合预期。所以,如果想自定义类型,果断选择 ”typedef“ 放弃宏定义,否则吃亏的是自己。

[!--infotagslink--]

相关文章

  • C#创建自定义控件及添加自定义属性和事件使用实例详解

    这篇文章主要给大家介绍了关于C#创建自定义控件及添加自定义属性和事件使用的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用C#具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧...2020-06-25
  • JS实现自定义简单网页软键盘效果代码

    本文实例讲述了JS实现自定义简单网页软键盘效果。分享给大家供大家参考,具体如下:这是一款自定义的简单点的网页软键盘,没有使用任何控件,仅是为了练习JavaScript编写水平,安全性方面没有过多考虑,有顾虑的可以不用,目的是学...2015-11-08
  • Vue 组件复用多次自定义参数操作

    这篇文章主要介绍了Vue 组件复用多次自定义参数操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-07-27
  • android自定义动态设置Button样式【很常用】

    为了增强android应用的用户体验,我们可以在一些Button按钮上自定义动态的设置一些样式,比如交互时改变字体、颜色、背景图等。 今天来看一个通过重写Button来动态实...2016-09-20
  • Android自定义WebView网络视频播放控件例子

    下面我们来看一篇关于Android自定义WebView网络视频播放控件开发例子,这个文章写得非常的不错下面给各位共享一下吧。 因为业务需要,以下代码均以Youtube网站在线视...2016-10-02
  • 自定义jquery模态窗口插件无法在顶层窗口显示问题

    自定义一个jquery模态窗口插件,将它集成到现有平台框架中时,它只能在mainFrame窗口中显示,无法在顶层窗口显示. 解决这个问题的办法: 通过以下代码就可能实现在顶层窗口弹窗 复制代码 代码如下: $(window.top.documen...2014-05-31
  • 自定义feignClient的常见坑及解决

    这篇文章主要介绍了自定义feignClient的常见坑及解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-10-20
  • pytorch 自定义卷积核进行卷积操作方式

    今天小编就为大家分享一篇pytorch 自定义卷积核进行卷积操作方式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-05-06
  • PHP YII框架开发小技巧之模型(models)中rules自定义验证规则

    YII的models中的rules部分是一些表单的验证规则,对于表单验证十分有用,在相应的视图(views)里面添加了表单,在表单被提交之前程序都会自动先来这里面的规则里验证,只有通过对其有效的限制规则后才能被提交,可以很有效地保证...2015-11-24
  • jquery自定义插件开发之window的实现过程

    这篇文章主要介绍了jquery自定义插件开发之window的实现过程的相关资料,需要的朋友可以参考下...2016-05-09
  • C#自定义事件监听实现方法

    这篇文章主要介绍了C#自定义事件监听实现方法,涉及C#事件监听的实现技巧,具有一定参考借鉴价值,需要的朋友可以参考下...2020-06-25
  • c#之用户定义的数据类型转换介绍

    c#允许定义自己的数据类型,这意味着需要某些工具支持在自己的数据类型间进行数据转换。方法是把数据类型转换定义为相关类的一个成员运算符,数据类型转换必须声明是隐式或者显式,以说明怎么使用它...2020-06-25
  • 使用BindingResult 自定义错误信息

    这篇文章主要介绍了使用BindingResult 自定义错误信息,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-10-23
  • 微信小程序 Toast自定义实例详解

    这篇文章主要介绍了微信小程序 Toast自定义实例详解的相关资料,需要的朋友可以参考下...2017-01-23
  • 在Vue中获取自定义属性方法:data-id的实例

    这篇文章主要介绍了在Vue中获取自定义属性方法:data-id的实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-09-09
  • SQL 尚未定义空闲 CPU 条件 - OnIdle 作业计划将不起任何作用

    今天在配置sql server 代理服务器的计划任务的时候发现了日志中提示这个SQL 尚未定义空闲 CPU 条件 - OnIdle 作业计划将不起任何作用信息导致无法执行计划任务,那么可以按照下面的方法解决即可...2021-07-16
  • pytorch 自定义参数不更新方式

    今天小编就为大家分享一篇pytorch 自定义参数不更新方式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-04-29
  • thinkphp自定义权限管理之名称判断方法

    下面小编就为大家带来一篇thinkphp自定义权限管理之名称判断方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2017-04-03
  • Nginx自定义访问日志的配置方式

    Nginx日志主要分为两种:访问日志和错误日志。访问日志主要记录客户端访问Nginx的每一个请求,格式可以自定义。下面这篇文章主要给大家介绍了Nginx自定义访问日志的配置方式,需要的朋友可以参考学习,下面来一起看看吧。...2017-07-06
  • php中header自定义404状态错误页面

    404页面就是一个告诉搜索引擎这个页面不存在了,同时也提示用户可以选择其它的操作了,下面我来给没有apache操作权限朋友介绍php中自定义404页面的操作方法。 方法一...2016-11-25