美文网首页
预处理阶段能做什么:宏定义和条件编译

预处理阶段能做什么:宏定义和条件编译

作者: Drew_MyINTYRE | 来源:发表于2021-06-19 15:08 被阅读0次

预处理指令只有十来个,实在是少得可怜。而且,常用的也就是 #include、#define、#if,所以很容易掌握。预处理指令都以符号“#”开头,这个你应该很熟悉了。但同时你也应该意识到,虽然都在一个源文件里,但它不属于 C++ 语言,它走的是预处理器,不受 C++ 语法规则的约束。

你在写预处理代码的时候,可以参考这个格式。

#                              // 预处理空行
#if __linux__                  // 预处理检查宏是否存在
#   define HAS_LINUX    1      // 宏定义,有缩进
#endif                         // 预处理条件语句结束
#                              // 预处理空行

在写头文件的时候,为了防止代码被重复包含,通常要加上“Include Guard”,也就是用“#ifndef/#define/#endif”来保护整个头文件,建议你在所有头文件里强制使用,像下面这样:

#ifndef _XXX_H_INCLUDED_
#define _XXX_H_INCLUDED_

...    // 头文件内容

#endif // _XXX_H_INCLUDED_

宏定义(#define/#undef)

宏的展开、替换发生在预处理阶段,不涉及函数调用、参数传递、指针寻址,没有任何运行期的效率损失,所以对于一些调用频繁的小代码片段来说,用宏来封装的效果比 inline 关键字要更好,因为它真的是源码级别的无条件内联。

#define ngx_tolower(c)      ((c >= 'A' && c <= 'Z') ? (c | 0x20) : c)
#define ngx_toupper(c)      ((c >= 'a' && c <= 'z') ? (c & ~0x20) : c)

#define ngx_memzero(buf, n)       (void) memset(buf, 0, n)

宏是没有作用域概念的,永远是全局生效。对于一些用来简化代码、起临时作用的宏,最好是用完后尽快用“#undef”取消定义,避免冲突的风险。

#define CUBE(a) (a) * (a) * (a)  // 定义一个简单的求立方的宏

cout << CUBE(10) << endl;        // 使用宏简化代码
cout << CUBE(15) << endl;        // 使用宏简化代码

#undef CUBE                      // 使用完毕后立即取消定义

另一种做法是宏定义前先检查,如果之前有定义就先 undef,然后再重新定义:

#ifdef AUTH_PWD                  // 检查是否已经有宏定义
#  undef AUTH_PWD                // 取消宏定义
#endif                           // 宏定义检查结束
#define AUTH_PWD "xxx"           // 重新宏定义

虽然不少人认为,定义常量更应该使用 enum 或者 const,但我觉得宏定义毕竟用法简单,也是源码级的真正常量,而且还是从 C 继承下来的传统,用在头文件里还是有些优势的。

#define MAX_BUF_LEN    65535
#define VERSION        "1.0.18"

条件编译(#if/#else/#endif)

你必须知道的一个宏是“__cplusplus”,它标记了 C++ 语言的版本号,使用它能够判断当前是 C 还是 C++,是 C++98 还是 C++11。你可以看下面这个例子

#ifdef __cplusplus                      // 定义了这个宏就是在用C++编译
    extern "C" {                        // 函数按照C的方式去处理
#endif
    void a_c_function(int a);
#ifdef __cplusplus                      // 检查是否是C++编译
    }                                   // extern "C" 结束
#endif

#if __cplusplus >= 201402                // 检查C++标准的版本号
    cout << "c++14 or later" << endl;    // 201402就是C++14
#elif __cplusplus >= 201103              // 检查C++标准的版本号
    cout << "c++11 or before" << endl;   // 201103是C++11
#else   // __cplusplus < 201103          // 199711是C++98
#   error "c++ is too old"               // 太低则预处理报错
#endif  // __cplusplus >= 201402         // 预处理语句结束

条件编译还有一个特殊的用法,那就是,使用“#if 1”“#if 0”来显式启用或者禁用大段代码,要比“/* … */”的注释方式安全得多,也清楚得多,这也是我的一个“不传之秘”。

#if 0          // 0即禁用下面的代码,1则是启用
  ...          // 任意的代码
#endif         // 预处理结束

#if 1          // 1启用代码,用来强调下面代码的必要性
  ...          // 任意的代码
#endif         // 预处理结束

相关文章

  • 预处理阶段能做什么:宏定义和条件编译

    预处理指令只有十来个,实在是少得可怜。而且,常用的也就是 #include、#define、#if,所以很容易掌...

  • 10/19

    今天老师讲了预处理命令,宏定义分为无参宏定义,带参宏定义和条件编译。宏定义包括宏名和宏展开,和函数相比预处理有很多...

  • 预处理指令

    0. 理解 定义: 文件在 预处理阶段 的操作 形式: 以 # 号开头 分类: 宏定义、条件编译 和 文件包含 1...

  • 10.19

    今天主要讲了预处理 主要是预处理的概念和预处理命令的使用 包括宏定义“文件包含”处理条件编译等等宏定义是老师重...

  • C语言内存分区

    运行之前 编译一个C程序会经历下面几个阶段: 预处理:宏定义展开,头文件展开,条件编译(#ifdef之类),不检查...

  • 2017年10月19日学校总结

    今天学习了预处理指令,预处理指令包括宏定义,条件编译,文件包含 宏定义,不占用内存空间。 #define p 3....

  • C 预处理

    C 语言提供了三种预处理功能:宏定义、文件包含、条件编译。这些操作都在预处理阶段完成,因此他们只做替换,不进行计算...

  • Day12

    预处理指令 宏定义 基本格式 不带参数的宏定义 带参数的宏定义 宏定义的作用域 条件编译 基本格式 应用场景用来替...

  • C语言 枚举类型和预处理指令

    枚举的定义 预处理指令 所有的预处理指令都是以#开头 预处理指令分为三种 宏定义 条件编译 文件包含 预处理指令在...

  • 打卡7.23:宏定义

    宏定义的三种预处理包括:宏定义、文件包含、条件编译 if是条件语句,在运行的过程中根据条件的值选择执行不同的语句。...

网友评论

      本文标题:预处理阶段能做什么:宏定义和条件编译

      本文链接:https://www.haomeiwen.com/subject/bjzryltx.html