From 1c74f156bfa815d142f0e82ecb633abdcea5fd93 Mon Sep 17 00:00:00 2001 From: lion187 Date: Tue, 10 Jul 2018 11:47:07 +0800 Subject: [PATCH] =?UTF-8?q?=E7=BC=96=E5=86=99=E9=AB=98=E7=BA=A7=E5=AE=8F?= =?UTF-8?q?=E6=93=8D=E4=BD=9C=E7=9A=84=E9=83=A8=E5=88=86=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Chapter2 C与C++/2.4 高级宏操作.md | 97 ++++++++++++++++++++++++++++++- 1 file changed, 96 insertions(+), 1 deletion(-) diff --git a/Chapter2 C与C++/2.4 高级宏操作.md b/Chapter2 C与C++/2.4 高级宏操作.md index 2238313..043148f 100644 --- a/Chapter2 C与C++/2.4 高级宏操作.md +++ b/Chapter2 C与C++/2.4 高级宏操作.md @@ -1 +1,96 @@ -条件编译 \ No newline at end of file +## 2.4 高级宏操作 + +“魔术是什么?魔术是错觉。但是错觉是为了给人带来快乐,娱乐和灵感。这是关于信仰、信念、信任。脱离了这些属性,魔术就不再是一种艺术了。” + ——《惊天魔盗团》 + +之前我们把宏理解为简单替换,实际上还有很多更神奇的宏操作,他们像程序里的魔术师一样,让人惊讶,神往,想一探究竟。但请切记:“The closer you look, the less you see。” + +### 2.4.1 条件编译 + +宏的第一个魔术,便是保护唯一性,常常在头文件里看到类似下面的内容: + +```cpp +/** + * @file some.h + */ +#ifndef SOME_H +#define SOME_H + +/* some codes... */ + +#endif + +``` + +在这样的文件中,也许我们会 tyoedef 一些类型,也有可能 define 一些宏,例如: “#define PI 3.1415”。然后在项目的其他文件里,会发现有好多:“#include “some.h””的地方,我们肆无忌惮的使用,甚至在某个文件中两次或者多次包含了 some.h 这个文件。在这种情况下,是否意味着 PI 被重复定义了多次呢? + +如果 PI 在某个文件中被重复定义,那么编译器会报错。当我们实际编译这样的项目时,发现并没有错误。这说明:在一个文件中,两次 include 了 some.h,但是其内容只被包含入了一次。 + +这是怎么做到的?当了解了条件编译之后,你就会理解了。 + +C/C++中的下列宏可以控制编译器的行为: + +```cpp +#if 整形常量表达式1 +   程序段1 +#elif 整形常量表达式2 +   程序段2 +#else +   程序段3 +#endif + + +#if defined 宏名1 +   程序段1 +#elif defined 宏名2 +   程序段2 +#else +   程序段3 +#endif + + +#ifdef 宏名 +   程序段1 +#else +   程序段2 +#endif + + +#ifndef 宏名 +   程序段1 +#else +   程序段2 +#endif +``` + +上面的宏告诉编译器,只在满足条件的情况下去编译特定的代码。不满足条件的话,对应代码不被编译。 + +现在,我们回来解析 some.h 文件:如果没有定义 SOME_H 这个宏,则定义一个 SOME_H 这个宏,并且声明“/* some codes... */”中的内容,如定义了 PI 这个宏。如果谋文件两次以上包含了 some.h 这个文,则从第二次开始,会发现之前已经定义过 SOME_H 宏,因此后续的判断都会失败,从而保证 some.h 中的内容只被包含一次。 + +*注意:some.h 中的保护范围实际上是从 #ifdef 开始到 #endif 结束。在此范围之外的内容仍会被多次包含* + +条件编译除了被用在头文件中用于避免重复引用外,还被经常被用于增加程序的通用性和可移植性上。如硬件平台有部分差异,造成项目的少部分代码有所不同,此时可以使用条件编译,将有差异的代码放到不同的条件下。对应不同硬件,可以人为改变编译条件,确保编译出对应硬件平台的程序。 + +### 2.4.2 宏函数 + +接下来让我们展示一些高级魔术 + +```cpp +// TODO: 完善示例,增加do while和...可变参数. + +#define abc(x, y) x##y + +abc(cr, 0) +abc(cr, 1) +``` + +### 2.4.3 编译器内置宏 + +宏这个魔术师有一些内置技能 +__FILE__ +__LINE__ +__FUNCTION__ +__DATE__ +__TIME__ + +### 练习