文章目录
- 前言
- 预处理器
- #define预处理
- 条件编译
- #ifdef
- #ifndef
- #if、#elif、#else 和 #endif
- #和##运算符
- 预定义宏
前言
预处理器
预处理器是指一些指示编译器在实际编译之前所需要完成的指令。
预处理器负责处理以**井号(#)**开头的预处理指令,这些指令在编译过程之前对源代码进行一些文本替换和操作。
例如#include <iostream>
除此之外,还有#define、#if、#else、#line 等
#define预处理
#define: 用于定义宏,将一个标识符替换为特定的文本。宏在代码中可以起到类似函数的作用,但是是在编译时进行文本替换的。
#define PI 3.14159
示例:
#include <iostream>
// 定义常量 PI
#define PI 3.14159
int main() {
// 使用定义的常量 PI
double radius = 5.0;
double area = PI * radius * radius;
// 输出计算结果
std::cout << "半径为 " << radius << " 的圆的面积是: " << area << std::endl;
return 0;
}
在上述中,用了#define PI 3.14159 这样预处理器会将所有出现的PI替换成3.14159,实际上,编译器处理的代码应该是:
double area = 3.4159 * radius * radius;
除了用#define定义常量的宏之外,还可以定义带有参数的宏;
如:
#include <iostream>
// 定义带参数的宏
#define MAX(x, y) ((x) > (y) ? (x) : (y))
int main() {
int a = 10, b = 7;
// 使用定义的宏
int result = MAX(a, b);
// 输出计算结果
std::cout << "较大的数是: " << result << std::endl;
return 0;
}
在实际编译时,预处理器会将所有的MAX(a, b)替换为((a) > (b) ? (a) : (b)),从而实现参数的替换和宏的展开。
条件编译
条件编译: 使用#if、#ifdef、#ifndef、#elif、#else和#endif等指令来根据条件选择性地包含或排除代码块。
#ifdef
#ifdef 是一个预处理器指令,用于在编译时检查一个标识符是否已经被定义。如果指定的标识符已经定义,则预处理器会包含后续的代码块,否则会忽略这个代码块。
使用示例:
#include <iostream>
// 定义一个标识符
#define DEBUG_MODE
int main() {
// 检查标识符是否已经定义
#ifdef DEBUG_MODE
std::cout << "Debug mode is enabled." << std::endl;
#else
std::cout << "Debug mode is disabled." << std::endl;
#endif
return 0;
}
在上述中使用了#define DEBUG_MODE 预定义了一个标识符,后面在main函数中,通过#ifdef DEBUG_MODE来检查。如果存在就会打印Debug mode is enabled.
上述运行结果:
如果我们将#define DEBUG_MODE注释掉,就会有
#ifndef
这个和#ifdef正好是相反的结果,即如果给定的标识符尚未被定义,则包括代码块。
#if、#elif、#else 和 #endif
这些预处理器指令允许根据条件选择性地包括或排除代码块。
示例:
#include <iostream>
#define DEBUG_LEVEL 2
int main() {
#if DEBUG_LEVEL == 0
std::cout << "No debugging." << std::endl;
#elif DEBUG_LEVEL == 1
std::cout << "Basic debugging." << std::endl;
#elif DEBUG_LEVEL == 2
std::cout << "Advanced debugging." << std::endl;
#else
std::cout << "Unknown debugging level." << std::endl;
#endif
return 0;
}
#和##运算符
#和 ## 是两个特殊的运算符,用于在宏定义中进行字符串化和连接操作。
#运算符(字符串化操作符): 在宏定义中,# 运算符可以将参数转换为字符串常量。在宏的定义中,将参数用 # 运算符括起来,预处理器会将参数的文本形式转换为字符串。
示例:
#define STRINGIZE(x) #x
int main() {
int value = 42;
const char* str = STRINGIZE(value);
// 在这里,str 的值为 "value"
return 0;
}
STRINGIZE(value) 会被替换为 “value”,因为 #x 将参数 x 转换为字符串。
##运算符(连接操作符): 在宏定义中,## 运算符用于将两个标识符连接在一起,形成一个新的标识符。
#define CONCAT(a, b) a##b
int main() {
int xy = 42;
// 在这里,CONCAT(x, y) 会被替换为 xy
return 0;
}
在上述代码中,CONCAT(x, y) 会被替换为 xy,因为 a##b 将两个参数 a 和 b 连接在一起。
预定义宏
C++ 中有一些预定义的宏,它们由编译器提供,并可在程序中直接使用。这些宏通常用于提供有关编译环境和代码特性的信息。
例如:
- __cplusplus: 这个宏用于指示 C++ 的版本。如果程序是在 C++ 编译器中编译的,__cplusplus 的值会被设置为一个表示 C++ 版本的整数。
- FILE: 这个宏会被替换为当前源文件的文件名。
- LINE: 这个宏会被替换为当前源文件中的行号。
- func 或 FUNCTION: 这个宏会被替换为当前函数的名称。
- DATE 和 TIME: 这两个宏会被替换为程序被编译时的日期和时间。
简短的示例:
#include <iostream>
using namespace std;
int main ()
{
cout << "Value of __LINE__ : " << __LINE__ << endl;
cout << "Value of __FILE__ : " << __FILE__ << endl;
cout << "Value of __DATE__ : " << __DATE__ << endl;
cout << "Value of __TIME__ : " << __TIME__ << endl;
return 0;
}
编译和运行后结果:
Value of __LINE__ : 6
Value of __FILE__ : test.cpp
Value of __DATE__ : Feb 28 2011
Value of __TIME__ : 18:52:48