【C++知识点】预处理命令

简介: 【C++知识点】预处理命令

预处理命令

预处理概述

预处理是 C++ 的一个重要功能, 预处理由预处理程序负责完成。

预处理是指在进行编译的第一遍扫描(词法扫描和语法分析)之前所作的工作。

当对一个源文件进行编译时, 系统把自动引用预处理程序对源程序中的预处理部分作处理,处理完毕自动进入对源程序的编译。


C++ 提供了多种预处理功能,例如宏定义、文件包含、 条件编译等。合理地使用预处理功能编写的程序便于阅读、修改、 移植和调试,还有就是利于模块化程序设计。


#include 其实就是一个预处理命令预处理,主要是处理以 # 开头的命令。预处理命令要放在所有函数之外,而且一般都放在源文件的前面。

常用预处理指令

//文件包含类
#include 包含一个源代码文件,头文件
//宏定义类
#define 定义宏
#undef 取消已定义的宏
//条件编译类
#if 如果给定条件为真,则编译下面代码
#ifdef 如果宏已经定义,则编译下面代码
#ifndef 如果宏没有定义,则编译下面代码
#elif 如果#if条件不为真,当前条件为真,则编译下面代码
#endif 结束#if...到 #else条件编译块

宏定义

C++ 源程序中允许用一个标识符来表示一个字符串,称为 “宏”。


被定义为宏的标识符称为 “宏名”。在编译预处理时,对程序中所有出现的宏名,都用宏定义中的字符串去代换,这称为宏替换或宏展开。


宏定义是由源程序中的宏定义命令完成的。


宏替换是由预处理程序自动完成的。在 C 语言中,宏定义分为有参数和无参数两种。

无参数宏定义

//语法
#define identify expression
#define 定义宏使用的关键字。
identify 宏的标识符,也就是宏名。
expression 该宏所代表的表达式或者常量值。    
//案例:
#define PI 3.14
//定义了一个宏 PI,其代表的常量值为 3.14,以后,我们需要使用 3.14 的地方,可以直接使用 PI 来代替。

案例

利用宏定义PI,输入半径r,完成求圆面积的代码。    
#define PI 3.1415926  
double r;
cin >> r;
cout << PI *r * r << endl;

带参数宏定义

//语法
#define identify(paramlist) expression
#define 定义宏使用的关键字。
identify 宏的标识符,也就是宏名。
paramlist 宏的参数列表。
expression 该宏所代表的表达式或者常量值。

案例

#define INC(x) x++
//定义了一个宏 INC,该宏接受一个参数 x,该宏实现的功能是将当前 x 的值自增
//案例1
#define INC(v) v++
#define DEC(v ) v--
int num= 100;
cout << “num = “ << num << endl;  //100
INC(num);
cout << “num = “ << num << endl;  //101
DEC(num);
cout << “num = “ << num << endl;  //100
//案例2
#define SQR(n) ((n)*(n))
int num = 10;
int result = SQR(num);
cout << result << endl; //100
int result2 = SQR(5 + 5);
cout << result2 << endl;  //100

在使用宏参数时,建议将所有的参数都是要 () 括起来。

像函数参数一样,在宏定义中的参数称为形式参数,在宏调用中的参数称为实际参数。

宏函数

C++ 中的宏函数,其实就是带参数的宏。

C++ 的宏函数跟普通函数类似,只是宏函数的参数没有类型

案例

利用宏函数,实现判断字符是否是十进制数字!    
#define DIGIT(c) ((c) >=’0’ && (c) <= ‘9’)
char ch1 = ‘a’;
char ch2 = ‘2’;
int d1 = DIGIT(ch1);
int d2 = DIGIT(ch2);
cout << d1 << endl; //0
cout << d2 << endl; //1

取消宏定义

定义了宏或者宏函数之后,如果不用了,可以使用 undef 取消定义宏和宏函数。

//语法
#undef MACRO_NAME

案例

#define PI 3.14
int main(){ 
    cout << "PI = " << PI << endl;
#undef PI
    cout << "PI = " << PI << endl; //报错
    return 0;
}
//#undef 取消定义了宏,取消定义宏之后,不可以再次访问该宏

条件编译

有些时候,希望当满足某条件时对一组语句进行编译,而当条件不满足时则编译另一组语句。条件编译功能可按不同的条件去编译不同的程序部分,从而产生不同的目标代码文件。这对于程序的移植和调试是很有用的。


在 C++ 中,一般情况下,源程序中所有的行都参加编译。但有时希望对其中一部分内容只在满足一定条件才进行编译,也就是对一部分内容指定编译的条件,这就是 “条件编译”。


条件编译作用

1.屏蔽跨平台差异

在大规模开发过程中,特别是跨平台和系统的软件里,可以在编译时通过条件编译设置编译环境。


2.包含程序功能模块

可以使用 #ifdef 实现包含程序的不同的功能模块。


3.开关调试信息

调试程序时,常常希望输出一些所需的信息以便追踪程序的运行。而在调试完成后不再输出这些信息,可以通过条件编译控制。


4.防止头文件重复包含

头文件(.h)可以被头文件或 CPP 文件包含。由于头文件包含可以嵌套,CPP 文件就有可能多次包含同一个头文件;或者不同的 CPP 文件都包含同一个头文件,编译时就可能出现重复包含(重复定义)的问题。


#ifdef

C++ 的 #ifdef 用于判断,如果一个标识符已被 #define 命令定义过,那么就编译该段代码,否则不编译。同时,#ifdef 还可以配合 #else一起使用。

//语法
#ifdef identity 
  code1
#endif
//如果标识符 identity 被定义过了,那么就编译代码 code1,否则就不编译。                
//语法
#ifdef identity 
  code1
#else 
    code2
#endif
//如果标识符 identity 被定义过了,那么就编译代码 code1,否则就编译代码 code2。 

案例

//案例1
#include <iostream>
using namespace std;
int main(){ 
    cout << "测试条件编译" << endl;
#ifdef PRINT 
    cout << "PRINT has defined" << endl;
#endif
    return 0;
}
//案例2
#include <iostream>
using namespace std;
int main(){ 
    cout << "条件编译测试2" << endl;
#ifdef PR
    cout << "PR has defined" << endl;
#else 
    cout << "PR not defined" << endl;
#endif 
    return 0;
}

#ifndef

#ifndef正好和#ifdef反过来,用于判断,如果一个标识符没有被#define 命令定义过,那么就编译该段代码,否则不编译。就是if not define的意思。

//语法
#ifndef identity 
    code1
#endif
//如果标识符 identity 未被定义过,那么就编译代码 code1,否则就不编译。
//语法
#ifndef identity 
    code1
#else 
    code2
#endif
//#ifndef 也可以配合 #else 一起使用,这里说明,如果标识符 identity未被定义过,那么就编译代码 code1,否则就编译代码 code2。

案例

//案例1
#include <iostream>
using namespace std;
int main(){ 
    cout << "条件编译测试3" << endl;
#ifndef PR 
    cout << "PR not defined" << endl;
#endif
    return 0;
}
//案例2
#include <iostream>
using namespace std;
int main(){
    cout << "条件编译测试4" << endl;
#ifndef PR 
    cout << "PR not defined" << endl;
#else
    cout << "PR has defined" << endl;
#endif 
    return 0;
}

#if

C++ 的 #if 后面可以接常量表达式,如果常量表达式的值为真(非0),则对一段程序进行编译,否则对另一段程序进行编译。因此可使程序在不同条件下,完成不同的功能。

//语法1
#if expression 
    code1
#endif
//语法2
#if expression 
    code1
#else 
    code2
#endif

案例

//案例1
#include <iostream>
using namespace std;
int main(){ 
    cout << "条件编译测试5" << endl;
#define com 0
#if com 
    cout << "Start compile" << endl;
#endif
    return 0;
}
//案例2
#include <iostream>
using namespace std;
int main(){ 
    cout << "条件编译测试5" << endl;
#define com 0
#if com 
    cout << "Start compile" << endl;
#else 
    cout << “ do not compile” << endl;
#endif
    return 0;
}

#elif

#elif可以跟在#if,#ifdef #ifndef的后面,但#else只能跟在最后面,用法和基本的条件语句类似。

案例

#include <iostream>
using namespace std;
int main() { 
    cout << "条件编译测试" << endl;
#define BY 0
#define BA 0
#if BY
    cout << "BY has define" << endl;
#elif BA
    cout << "BA is 1" << endl;
#endif
    return 0;}

#error

#error 用于在编译期间给出一个错误信息,并终止程序的编译。同时,#error 后面的错误信息不需要使用双引号。

//语法
#error error message

案例

#include <iostream>
using namespace std;
int main() { 
    cout << "条件编译测试" << endl
#error compile error here! 
    return 0;
}
目录
相关文章
|
6月前
|
存储 人工智能 算法
【一站式备考指南】一文掌握 C++ 程序设计 课程 知识点
【一站式备考指南】一文掌握 C++ 程序设计 课程 知识点
128 0
|
6月前
|
编译器 程序员 Linux
C++系列九:预处理功能
C++系列九:预处理功能
|
4月前
|
编解码 NoSQL Redis
c++开发redis module问题之想实现Redis命令,如何解决
c++开发redis module问题之想实现Redis命令,如何解决
|
4月前
|
NoSQL Java 编译器
c++开发redis module问题之保证Redis在fork时没有处于inflight状态的命令,如何解决
c++开发redis module问题之保证Redis在fork时没有处于inflight状态的命令,如何解决
|
5月前
|
存储 网络协议 编译器
【干货总结】Linux C/C++面试知识点
Linux C/C++基础与进阶知识点,不仅用于面试,平时开发也用得上!
570 14
|
4月前
|
NoSQL Redis C++
c++开发redis module问题之对于写命令,进行主备复制和写AOF,如何解决
c++开发redis module问题之对于写命令,进行主备复制和写AOF,如何解决
|
5月前
|
C++
C++继承的相关知识点
C++继承的相关知识点
28 0
|
6月前
|
C++
【C++小小知识点】重载、覆盖(重写)、隐藏(重定义)的对比【详解】(23)
【C++小小知识点】重载、覆盖(重写)、隐藏(重定义)的对比【详解】(23)
|
6月前
|
存储 算法 搜索推荐
【C++ 数据结构与算法 一站式备考指南】一文掌握 数据结构与算法课程 知识点(二)
【C++ 数据结构与算法 一站式备考指南】一文掌握 数据结构与算法课程 知识点
153 2
|
6月前
|
存储 算法 C++
【C++ 数据结构与算法 一站式备考指南】一文掌握 数据结构与算法课程 知识点(一)
【C++ 数据结构与算法 一站式备考指南】一文掌握 数据结构与算法课程 知识点
238 2