• C++学习贴---C++预处理器


    前言


    预处理器

    预处理器是指一些指示编译器在实际编译之前所需要完成的指令。

    预处理器负责处理以**井号(#)**开头的预处理指令,这些指令在编译过程之前对源代码进行一些文本替换和操作。

    例如#include 
    
    • 1

    除此之外,还有#define、#if、#else、#line 等


    #define预处理

    #define: 用于定义宏,将一个标识符替换为特定的文本。宏在代码中可以起到类似函数的作用,但是是在编译时进行文本替换的。

    #define PI 3.14159
    
    • 1

    示例:

    #include 
    
    // 定义常量 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;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    在上述中,用了#define PI 3.14159 这样预处理器会将所有出现的PI替换成3.14159,实际上,编译器处理的代码应该是:

    double area = 3.4159  * radius * radius;
    
    • 1

    除了用#define定义常量的宏之外,还可以定义带有参数的宏;

    如:

    #include 
    
    // 定义带参数的宏
    #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;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    在实际编译时,预处理器会将所有的MAX(a, b)替换为((a) > (b) ? (a) : (b)),从而实现参数的替换和宏的展开。


    条件编译

    条件编译: 使用#if、#ifdef、#ifndef、#elif、#else和#endif等指令来根据条件选择性地包含或排除代码块。

    #ifdef

    #ifdef 是一个预处理器指令,用于在编译时检查一个标识符是否已经被定义。如果指定的标识符已经定义,则预处理器会包含后续的代码块,否则会忽略这个代码块。

    使用示例:

    #include 
    
    // 定义一个标识符
    #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;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    在上述中使用了#define DEBUG_MODE 预定义了一个标识符,后面在main函数中,通过#ifdef DEBUG_MODE来检查。如果存在就会打印Debug mode is enabled.

    上述运行结果:
    在这里插入图片描述
    如果我们将#define DEBUG_MODE注释掉,就会有
    在这里插入图片描述

    #ifndef

    这个和#ifdef正好是相反的结果,即如果给定的标识符尚未被定义,则包括代码块。

    #if、#elif、#else 和 #endif

    这些预处理器指令允许根据条件选择性地包括或排除代码块。

    示例:

    #include 
    
    #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;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    #和##运算符

    #和 ## 是两个特殊的运算符,用于在宏定义中进行字符串化和连接操作。

    #运算符(字符串化操作符): 在宏定义中,# 运算符可以将参数转换为字符串常量。在宏的定义中,将参数用 # 运算符括起来,预处理器会将参数的文本形式转换为字符串。

    示例:

    #define STRINGIZE(x) #x
    
    int main() {
        int value = 42;
        const char* str = STRINGIZE(value);
        // 在这里,str 的值为 "value"
        return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    STRINGIZE(value) 会被替换为 “value”,因为 #x 将参数 x 转换为字符串。

    ##运算符(连接操作符): 在宏定义中,## 运算符用于将两个标识符连接在一起,形成一个新的标识符。

    #define CONCAT(a, b) a##b
    
    int main() {
        int xy = 42;
        // 在这里,CONCAT(x, y) 会被替换为 xy
        return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在上述代码中,CONCAT(x, y) 会被替换为 xy,因为 a##b 将两个参数 a 和 b 连接在一起。


    预定义宏

    C++ 中有一些预定义的宏,它们由编译器提供,并可在程序中直接使用。这些宏通常用于提供有关编译环境和代码特性的信息。

    例如:

    • __cplusplus: 这个宏用于指示 C++ 的版本。如果程序是在 C++ 编译器中编译的,__cplusplus 的值会被设置为一个表示 C++ 版本的整数。
    • FILE: 这个宏会被替换为当前源文件的文件名。
    • LINE: 这个宏会被替换为当前源文件中的行号。
    • funcFUNCTION: 这个宏会被替换为当前函数的名称。
    • DATETIME: 这两个宏会被替换为程序被编译时的日期和时间。

    简短的示例:

    #include 
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    编译和运行后结果:

    Value of __LINE__ : 6
    Value of __FILE__ : test.cpp
    Value of __DATE__ : Feb 28 2011
    Value of __TIME__ : 18:52:48
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
  • 相关阅读:
    Shader中需要数学知识
    ARM DIY(九)陀螺仪调试
    爬虫记录——第三方钱包加密参数逆向
    Java中如何实现定时任务?
    数据库表中创建字段查询出来却为NULL?
    NFT数字藏品交易平台开发
    在Linux(Centos7)上编译whisper.cpp的详细教程
    目标检测YOLO实战应用案例100讲-面向辅助驾驶的道路目标检测(中)
    【无标题】
    AIRIOT亮相IOTE2023深圳物联网展,产品创新力再获“IOTE金奖”
  • 原文地址:https://blog.csdn.net/Sciurdae/article/details/134342222