45.宏

45.宏


45.1 知识点

知识点回顾:什么是编译器

编译器是一种翻译程序,用于将源语言程序翻译为目标语言程序。编译器的主要任务是将人类可读的代码转换为计算机能执行的指令。

  • 源语言程序:由某种程序设计语言编写的程序,例如 C++、C#、C、Java 等语言写的程序。
  • 目标语言程序:机器代码或中间代码,是计算机可以识别和理解的内容。

什么是预处理指令

预处理器指令指导编译器在实际编译开始之前对信息进行预处理。预处理器指令都以 # 开始,并且它们不是语句,因此不以分号 ; 结束。我们经常用到的折叠代码块就是一种预处理器指令。

宏的基本概念

宏是一种预处理指令,主要作用是在编译之前替代源代码中的信息。它类似于一连串信息的别名(这些信息可以是数值、字符串、表达式等)。宏主要通过 #define 指令来创建,并且分为不带参数的宏和带参数的宏。

  • 使用注意:

    • 宏一般写在代码文件的最上方(#include 下方)。
    • 宏命名通常使用大写字母。
    • 宏定义后不需要在行末加分号 ;

宏的使用:不带参数的宏

#define PI 3.1415926
#define MAX_SIZE 100
#define COUT_HELLO cout << "Hello, World" << endl
#define INFO "信息"

基本语法

#define 宏名 用于替代的信息

主要作用

  • 定义常量或简化代码中的重复部分。
cout << PI << endl; // 3.1415926
double default2 = PI * 3;
cout << default2 << endl; // 9.42478

COUT_HELLO; // Hello, World

string str = INFO;
cout << str << endl; // 信息

宏的使用:带参数的宏

#define MUL1(x, y) x * y
#define ADD1(x, y) x + y
#define MUL2(x, y) (x) * (y)
#define ADD2(x, y) (x + y)

基本语法

#define 宏名(参数) 参数使用表达式

主要作用

  • 简化表达式、代码重用、条件表达式、避免函数调用开销。

注意事项

  • 使用带参数的宏时要小心,因为它们不会进行类型检查,相对来说,内联函数更安全。
  • 表达式中的括号使用要小心。
// 3 * 4 + 1 = 13
cout << MUL1(3, 4 + 1) << endl;//13
// 3 * 3 + 4 = 13
cout << 3 * ADD1(3, 4) << endl;//13

// 3 * 5 = 15
cout << MUL2(3, 4 + 1) << endl;//15
// 3 * 7 = 13
cout << 3 * ADD2(3, 4) << endl;//21

取消宏定义

#define UE4
#define UE5
#undef UE4
#undef UE5

#undef 用于取消宏定义,主要用于取消已定义的宏。

宏的使用:定义一个符号

基本语法

#define 符号

主要作用

定义一个符号,类似于一个没有值的变量,可以配合编译指令使用。

使用示例

使用宏来决定编译哪些代码,可以利用它来区分不同版本执行不同的代码等功能。

#ifdef UE4
    cout << "UE4要执行的逻辑" << endl;
#elif defined(UE5)
    cout << "UE5要执行的逻辑" << endl;
#else
    cout << "其他版本执行的逻辑" << endl;
#endif

宏的优缺点

优点:

  • 简化代码。
  • 条件编译。
  • 消除函数调用的开销。
  • 灵活性(没有类型限制)。
  • 便于全局修改。

缺点:

  • 增加调试难度:宏在代码中展开,调试时可能难以追踪错误,错误信息可能不够清晰。
  • 没有类型检查。
  • 命名冲突:可能会与其他变量或函数名冲突。
  • 缺乏作用域:宏没有作用域限制,它们在整个文件中有效。
  • 可读性下降:过度使用宏,尤其是在复杂的宏定义中,可能会导致代码难以理解和维护。

总结

虽然宏在编程中很有用,但当可以使用常量、内联函数、枚举等功能替代宏时,应该尽量避免使用宏。


45.2 知识点代码

Lesson45_宏.cpp

#include <iostream>

#pragma region 知识点三 宏的使用 不带参数的宏

#define PI 3.1415926
#define MAX_SIZE 100
#define COUT_HELLO cout << "Hello,World" << endl
#define INFO "信息"

#pragma endregion

#pragma region 知识点四 宏的使用 带参数的宏

//要注意括号的使用
#define MUL1(x,y) x*y
#define ADD1(x,y) x+y
#define MUL2(x,y) (x)*(y)
#define ADD2(x,y) (x+y)

#pragma endregion

#pragma region 知识点五 取消宏定义

#define UE4
#define UE5
#undef UE4
#undef UE5

#pragma endregion

using namespace std;

int main()
{
    std::cout << "宏\n";

    #pragma region 知识点回顾 什么是编译器

    //编译器是一种翻译程序
    //它用于将 源语言程序 翻译为 目标语言程序
    //编译器的主要任务是让人类可读的代码变成计算机能执行的指令

    //源语言程序:  某种程序设计语言写成的,比如C++、C#、C、Java等语言写的程序
    //目标语言程序: 机器代码或中间代码,让计算机等可以识别理解的内容

    #pragma endregion

    #pragma region 知识点一 什么是预处理指令

    //预处理器指令 指导编译器 在实际编译开始之前对信息进行预处理
    //预处理器指令 都是以#开始
    //预处理器指令不是语句,所以它们不以分号;结束
    //目前我们经常用到的 折叠代码块 就是预处理器指令

    #pragma endregion

    #pragma region 知识点二 宏的基本概念

    //宏就是一种预处理指令
    //它的主要作用就是在编译之前 替代源代码中的信息
    //类似一连串信息的别名(信息可以是数值、字符串、表达式等等)
    //宏主要通过
    //#define指令来创建
    //分为 不带参数的宏 和 带参数的宏

    //使用注意:
    //1.一般写在代码文件的最上方(#include下方)
    //2.宏命名一般全为大写
    //3.不需要在行末加分号;

    #pragma endregion

    #pragma region 知识点三 宏的使用 不带参数的宏

    //基本语法
    //#define 宏名 用于替代的信息
    //主要作用
    //定义常量或简化代码的重复部分
    cout << PI << endl;//3.1415926
    double default2 = PI * 3;
    cout << default2 << endl;//9.42478

    COUT_HELLO;//Hello,World

    string str = INFO;
    cout << str << endl;//信息

    #pragma endregion

    #pragma region 知识点四 宏的使用 带参数的宏

    //基本语法
    //#define 宏名(参数) 参数使用表达式
    //主要作用
    //简化表达式、代码重用、条件表达式、避免函数调用开销
    //注意事项
    //1.使用带参数的宏时要小心,因为它们不会进行类型检查
    //  相对来说,内联函数更安全
    //2.表达式中括号的重要性

    // 3 * 4 + 1 = 13
    cout << MUL1(3, 4 + 1) << endl;//13
    // 3 * 3 + 4 = 13
    cout << 3 * ADD1(3, 4) << endl;//13

    // 3 * 5 = 15
    cout << MUL2(3, 4 + 1) << endl;//15
    // 3 * 7 = 13
    cout << 3 * ADD2(3, 4) << endl;//21

    #pragma endregion

    #pragma region 知识点五 取消宏定义

    //undef 宏
    //undef表示取消宏
    //主要用在宏定义符号时使用

    #pragma endregion

    #pragma region 知识点六 宏的使用 定义一个符号

    //基本语法
    //#define 符号
    //主要作用
    //定义一个符号,类似一个没有值的变量
    //可以配合编译指令
    //#ifdef 宏
    //#elif defined(宏)
    //#else
    //#endif
    //使用
    //用宏来决定编译哪些代码
    //可以利用它来区分不同版本执行不同的代码等功能

    #ifdef UE4
    cout << "UE4要执行的逻辑" << endl;
    #elif defined(UE5)
    cout << "UE5要执行的逻辑" << endl;
    #else
    cout << "其他版本执行的逻辑" << endl;

    #endif

    #pragma endregion

    #pragma region 知识点七 宏的优缺点

    //优点:
    //1.简化代码
    //2.条件编译
    //3.消除函数调用的开销
    //4.灵活性(没有类型限制)
    //5.便于全局修改
    //等等

    //缺点:
    //1.增加调试难度
    //  宏在代码中展开,调试时可能难以追踪错误,错误信息可能不够清晰
    //2.没有类型检查
    //3.命名冲突  
    //  可能会与其他变量或函数名冲突
    //4.缺乏作用域
    //  宏没有作用域限制,它们在整个文件中有效
    //5.可读性下降
    //  过度使用宏,尤其是在复杂的宏定义中,可能会导致代码难以理解和维护
    //等等

    //宏虽然看起来挺有用
    //但是日后再使用时
    //如果能够被常量、内联函数、枚举等等功能替代宏功能时
    //就不要使用宏了

    #pragma endregion
}

45.3 练习题

请实现一个宏用于判断一个数是否是偶数

#define IS_EVEN(n) ((n) % 2 == 0)

请实现一个宏用于判断两个数谁更大

#define MAX(a, b) ((a) > (b) ? (a) : (b))

请实现一个宏用于计算一个数的平方

#define SQUARE(x) ((x) * (x))


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏