C/C++高级特性之——预处理器中的宏(Macro)#define 详解

 

宏(英语:Macro)是一种批量处理的称谓。
计算机科学里的宏是一种抽象(Abstraction),它根据一系列预定义的规则替换一定的文本模式。解释器或编译器在遇到宏时会自动进行这一模式替换。对于编译语言,宏展开在编译时发生,进行宏展开的工具常被称为宏展开器。
宏这一术语也常常被用于许多类似的环境中,它们是源自宏展开的概念,这包括键盘宏和宏语言。绝大多数情况下,“宏”这个词的使用暗示着将小命令或动作转化为一系列指令。
——摘自:百度百科

得,估计这段东西也没人要看,那我们就进入正题吧。

欢迎关注我的公众号:Huayu_IT!里面有许多编程和计算机的有趣知识哦~


 

 


本文为EricNTH的原创博客,转载请注明出处!


宏的定义

在最顶上,不看也罢。

C++中宏的用途

1.定义常量

语法

#define CONSTANT_NAME CONSTANT_VALUE

举个例子:

#define PI 3.1415926

替代方案

const double PI = 3.1415926

两种方法的利弊:
使用宏#define:使用方便快捷,且有许多方法。但是不是类型安全的。
使用const:语法比较长,但是类型安全。
可以自行挑选。

补充内容

你可以使用 #ifdef (#if defined) 或 #ifndef (#if not defined) 来检查常量是否有被定义。
你可以使用#undef来解除对一个常量的定义。
例如:

#ifdef PI
//do sth.
#endif

#ifndef PI
//do sth.
#endif

#undef PI //PI is not defined since then!

以上内容仅适用于#define宏,不适用于const。

2.多重包含防范

语法&示例

#ifndef MAIN_H
#define MAIN_H

#endif

用途

保证一个头文件不被多次包含,如例子中是main.h的方法,一般宏名起作文件名的大写,.等符号用_替换。

替代方案

#pragma once

这样与上面效果完全相同,而且比上面简介,不容易错。
推荐后者。

3.创建宏函数

语法

#define FUNCTION_NAME(PARAMETER LIST) somefunctions();\
	otherfunctions();

宏函数,是宏中难度较高的一部分了。
不太容易理解,而且很容易犯错。
下面就让我给大家讲一讲它的各种内容。

示例

#define MAX_THREE(a,b,c) (((a)>(b) ? \
	((a)>(c)?:(a):(c)):\
	((b)>(c)?:(b):(c))))

如果调用它(如:cout << MAX_THREE(1,x,2+3 << endl;),实际上编译器是进行了如下的操作:

cout << (((1)>(x)?((1)>(2+3)?:(1):(2+3)):((x)>(2+3)?:(x):(2+3)))) << endl;

其实我故意写麻烦了(其实直接max(a,max(b,c))就可以了,我这样写就是因为有东西要和大家讲。
顺便说一句,?:是条件三目运算符,不懂可以自行百度。

思路大家应该大家应该都能了解,主要我们来看一下里面的语法。

语法&注意事项

(1) \:宏函数可以通过\来扩展到下一行,最后一行不用加。适当使用\可以增强代码的可读性。
(2)MAX_THREE:宏的命名(按照惯例)应该全部大写,单词之间应该用下划线分隔开。宏名应该需要具有自我描述性。
(3)MAX_THREE(a,b,c):在形参与宏名这边一定不!要!加!空!格!!!否则99.99%出错!(否则编译器会识别为常量等,导致错乱)
(4)(a)(b)(c):在宏中使用参数时,两边一定要加括号!当传入的参数是一个数或变量时还好,若传入的是一个表达式,则在展开时会发生重大问题!
(5)整个表达式两边也要加括号!

替代方案

宏函数,最好的替代方案是模板(最新的ANSI C++标准全面支持),可以参见我的这篇Blog>>>

字符串化与字符串拼接(宏函数特有功能)

大家猜一猜,这些代码会输出什么结果?

#define PRINT(x) cout << #x << " = " << x << endl;
double num = 7.5;
PRINT(num);

答案在评论区哦!

#运算符可以将它后面跟着的那个东西字符串化。

还有拼接##运算符,和#是差不多的哟!我的这篇文章里面(在中间)有说明。

为什么不建议用宏

最重要的一点是:Macro不是类型安全的,这严重破坏了C++的强类型特征。
然后,宏不会出现在编译器生成的中间源代码中(它在编译初期预处理阶段就已经被替换掉了),因此难以调试。
而且,虽然简便,但大型宏非常难以管理(虽然可以用\扩展到下一行)。
最后,也并不重要,宏是C风格,不是C++风格。
建议大家看一下我的这篇博客,,里面也进行了说明。

为什么要保留宏

既然C++中宏的每个用途都有更好的替代方案,为什么还要保留它呢?
1.也是最重要的,C语言中宏是非常常用的,如宏函数等更是不可替代的(当时,模板是C++特性),而C++必须向后兼容C的全部特性。
2.有些方面,虽然替代方案更好,但可能宏更简短。
3.宏函数中字符串拼接,与字符串化等特性,只有宏支持,其它(模板函数)并不支持。


好了今天就讲到这里,谢谢大家!
本文为EricNTH的原创博客,转载请注明出处!

 

posted @ 2020-03-12 14:33  EricNTH  阅读(760)  评论(0编辑  收藏  举报