| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> C++知识库 -> 使用经验 56 使用#define定义字面值和伪函数 -> 正文阅读 |
|
[C++知识库]使用经验 56 使用#define定义字面值和伪函数 |
#define是C语言提供的宏定义命令,其主要目的:在编程时,为程序员提供一定方便,并能在一定程度上提高程序的执行效率。#define将一个标示符定义为一个字符串,该标示符被称为宏,被定义的字符串称为替换文本。宏定义一般有两种形式:一种是简单宏定义(即字面值),另一种是带参数宏定义(即常说的伪函数)。 简单的宏定义定义形式为:
例如:
说明:
在C语言中,通过简单的宏定义恒值常量,是C语言中定义恒值常量的唯一手段。但是在C++中这不在是唯一了,C++的const也可定义一个恒值常量。例如:
const定义的恒值常量比#define定义的恒值常量存在很多优点,两者的区别如下: (1)const定义常量是有数据类型,而#define定义的常量无数据类型 通过const定义的常量,编译器可对其进行静态类型安全检查,而#define宏定义的常量只是简单的字符替换,没有类型安全检查,且有时还会产生边际效应。所谓边际效应,举例如下:
当程序中使用 M*N 时,你期望的结果是:100 * (200+ N),而实际结果是:100 * 200 + N。而const常量就没有这些问题。 (2)有些调试程序可对const进行调试,但不无法对#define进行调试。 (3)当定义局部变量时,const作用域仅限于定义局部变量的函数体内。但#define其作用域不限于定义局部变量的函数体,而是从定义点到整个程序的结束点。但可用#undef取消其定义,从而限定其作用域范围。 (4)const定义常量,并不能起到其强大的作用。const还可修饰函数形式参数、返回值和类的成员函数等。从而提高函数的健壮性。因为const修饰的东西必须受c/c++的静态类型安全检查机制的强制保护,可防止意外的修改。 带参数的宏定义定义形式为:
例如:
标示符被定义为宏后,该标示符便是一个宏名。在程序中,出现宏名的地方,在程序被编译前,先将宏名用被定义的字符串替换,这被称为宏替换。替换后才进行编译,宏替换是简单字符替换。 说明:
例如:
这个宏真正的含义:S是符号常量(不带参数的宏名),它代表字符串“( r ) PI*r*r”。在程序中,语句:area = S(a);,将会被展开为:area = ( r ) PI*r*r(a);。这显然不对。 明白了带参数的宏定义,也许你会有这个感觉:带参数的宏,有点儿像函数,的确事实也是如此,带参数的宏和函数确实有很多的相同点和不同点。具体带参数的宏和函数有下述区别。
讨论了宏的两种定义形式,我们继续分享宏的引入给程序带来好处,以及宏定义和命名空间的关系。 (1)宏定义的引入可方便程序的修改。使用简单宏定义,可用宏替换那些在程序中经常使用的常量,当需要修改该常量时,不用对整个程序进行修改,只修改宏定义的字符串即可奏效,而且当常量比较长时, 我们可以用较短、有意义的标识符来编写程序,这样更方便一些。 此处所说的常量改变,不是指在程序运行期间改变,而是在编程期间的改变,举一个大家熟悉的例 子,圆周率π是在数学上常用的一个值,有时我们会用3.14表示,有时也会用3.1415926等,这要看计算所需要的精度,如果我们编制的程序多次使用它,那么需要确定一个数值,在本次运行中不改变,但也许后来发现程序所表现的精度有变化,需要改变它的值, 这就需要修改程序中所有的相关数值,这会给我们带来一定的不便,但如果使用宏定义,使用一个标识符来代替,则在修改时只修改宏定义即可,还可以减少输入3.1415926这样长的数值多次,我们如此定义#define PI 3.1415926,既减少输入,又便于修改,何乐而不为呢? (2)提高程序的运行效率。使用带参数的宏定义可完成函数调用的功能,又能减少系统开销,提高运行效率。正如C语言中所讲,函数的使用可以使程序更加模块化,便于组织,而且可重复利用,但在发生函数调用时,需要保留调用函数的现场,以便子函数执行结束后能返回继续执行,同样在子函数执行完后要恢复调用函数的现场,这都需要一定的时间,如果子函数执行的操作比较多,这种转换时间开销可以忽略,但如果子函数完成的功能比较少,甚至于只完成一点操作,如一个乘法语句的操作,则这部分转换开销就相对较大了,但使用带参数的宏定义就不会出现这个问题,因为它是在预处理阶段即进行了宏展开,在执行时不需要替换。宏定义可完成简单的操作,但复杂的操作还是要由函数调用来完成,而且宏定义所占用的目标代码空间相对较大。所以在使用时要依据具体情况决定是否使用宏定义。 (3)#define预处理器完全没把C++的作用域纳入考量,绝大多数C++实现都是封装在命名空间里,这样的做法有很多优点。但不幸的是,#define的作用域并未被限定在名字空间中,例如:
讨论一下,上述代码为什么是糟糕的实现?按照命名空间的原理,定义在Infuential空间中的MAX不能在空间之外使用。但由于MAX是宏定义,不受名字空间的限制。 最后,需要提醒的是,宏不仅可定义字面值和伪函数。另一个重要的用法是条件编译。在大规模的开发过程中,特别是跨平台和系统的软件里。可以在编译的时候,通过#define设置编译环境。例如:
请谨记
|
|
C++知识库 最新文章 |
【C++】友元、嵌套类、异常、RTTI、类型转换 |
通讯录的思路与实现(C语言) |
C++PrimerPlus 第七章 函数-C++的编程模块( |
Problem C: 算法9-9~9-12:平衡二叉树的基本 |
MSVC C++ UTF-8编程 |
C++进阶 多态原理 |
简单string类c++实现 |
我的年度总结 |
【C语言】以深厚地基筑伟岸高楼-基础篇(六 |
c语言常见错误合集 |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年4日历 | -2025/4/12 1:55:01- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |