首页 > 编程语言 >C++宏

C++宏

时间:2024-09-08 21:14:55浏览次数:4  
标签:int 代码 C++ 义宏 使用 define

  宏是编译时预处理阶段用到的一种强大的工具,宏可以实现对指定代码片段的替换。依照笔者的理解,宏实际上是给某个特定的代码段起了一个别名。在预处理阶段,编译器将代码中的这个别名替换成相应的代码段。在C++当中,我们可以使用#define指令来定义宏。

#define PI 3.14159265358979323846

  在这个宏中,就给3.14159265358979323846起了PI这样一个别名,在C++中,可以使用PI来替代圆周率,这样代码看上去会更加清晰明了。

宏的作用

  常量替换

    如上文所述,使用宏可以实现代码常量的替换,避免使用魔数(magic numbers)的产生,提高代码的可读性。例如上面提到的圆周率这个例子,一般约定,常量的别名都是大写。

  实现简单的函数定义

    使用宏可以在一定程度上替代函数,在C++中,常常使用宏来替代简单的函数。例如下面这个例子:

#define MAX(x,y) ((x)>(y)?(x):(y))

    因为宏是纯粹的文本替换,在用它来代替函数时,如果使用不慎,可能造成意想不到的逻辑错误,例如下面这个例子。

1 // 错误的示例,使用宏实现平方根计算
2 #include <iostream>
3 #define AREA(x) x*x
4 
5 int main()
6 {
7     std::cout<<AREA(2+2)<<std::endl;
8     return 0;
9 }

    这段代码的预期结果是16,但他的实际运行结果是8。这是因为在宏替换之后,第七行的代码实际上变成了:

std::cout<<2+2*2+2<<std::endl;

    解决的方式是使用函数宏,给每个用到参数的地方加上括号。仅仅给参数加上括号是不够的,如果我们将AREA的结果作为除数,也可能产生替换错误。

1 // 错误的示例2 预期结果是4,实际是16
2 #include <iostream>
3 #define AREA(x) (x)*(x)
4 
5 int main()
6 {
7     std::cout<<AREA(2+2)/AREA(1+1)<<std::endl;
8     return 0;
9 }

    第7行的代码实际上变成了这样:

std::cout<<(2+2)*(2+2)/(1+1)*(1+1)<<std::endl;

    因此像函数一样使用宏时,我们需要给整个要替换的代码段加上括号。

#define AREA(x) ((x)*(x))

  多行宏

    在C++中,如果你需要将一个宏定义分成多行来写,可以使用反斜杠(\)来指示宏定义在下一行继续。另外,如果宏的内容比较复杂,那么建议使用do...while(0)结构将要替换的代码段包括起来。

 1 //多行宏
 2 #include<iostream>
 3 #define SWAP(x,y) \
 4     do {    \
 5         decltype(x) tmp;\
 6         tmp = x; \
 7         x = y; \
 8         y = tmp;\
 9     }while(0);
10 
11 int main()
12 {
13     int x = 1;
14     int y = 2;
15     SWAP(x,y);
16     std::cout<<"x:"<< x <<"   y:"<<y<<std::endl;
17     return 0;
18 }

    这样做的好处是可以将宏的内容成为一个独立的语法单元,避免调用时产生的错误。

  宏定义中的特殊符号的含义

    在C++的宏当中,有2个特殊符号。

  1. #:用来为参数加上双引号。
  2. ##:用来将两端内容连接在一起。
 1 // 宏当中的特殊符号
 2 #include<iostream>
 3 #define CONNECT(x,y) x##y 
 4 #define TOSTRING(x) #x
 5 
 6 int main()
 7 {
 8     int n = CONNECT(11,22);
 9     std::cout<<n<<std::endl;
10     std::string str = TOSTRING(Hello World);
11     std::cout<<str<<std::endl;
12     return 0;
13 }

运行结果如下:

 预定义宏

  gcc 的预处理器预定了很多宏,这些宏被称为“预定义宏”(Predefined Macros)。对于 C 语言,预定义宏包含三类:标准的(standard)、通用的(common)和特定于系统的(system-specific)。对于 C++ 语言,除了上述三类,还多了一类:命名运算符(named operators)。

  标准的预定义宏:由相关的语言标准指定,因此实现这些标准的所有编译器都可以使用它们。

  通用的预定义宏:GNU C 扩展的预定义宏。

  特定于系统的预定义宏:表示系统和机器类型的宏。

  命名运算符:在 C++ 中,有 11 个关键字,它们是常用标点符号的替代写法。即使在预处理器中,也可以使用这些关键词,如在 #if 中拿它们充当运算符。在 C 中,可以通过包含 iso646.h 来要求这些关键字具有 C++ 的含义。该头文件将它们定义为普通的宏,并扩展到相应的标点符号。

更多预定义宏的相关知识,可以参考链接:https://gcc.gnu.org/onlinedocs/cpp/Predefined-Macros.html#Predefined-Macros

   

总结:宏的优点和缺点

  优点

    • 使用宏能避免魔数(magic number),提示代码复用率。
    • 宏在编译时期展开,运行时没有开销。

  缺点

    • 使用宏会造成代码调试困难。
    • 宏不进行类型检测,容易造成类型错误。

标签:int,代码,C++,义宏,使用,define
From: https://www.cnblogs.com/xyhj/p/18403393

相关文章

  • C++变JAVE
    一、故事就是我今天闲的没事干,然后就突然想到了JAVE程序(就是我想到了用JAVE做菜单程序)然后就照着网上的教程然后就下载好了这个JDK-21#¥……&*&*O*&%……&K什么什么的东西,然后又让我在环境变量里修改一通后,他让我用下载地址打开cmd然后让我输入jave-version(不小心多打......
  • C++小游戏集合3个(不定时更新)1
    前言在Dvec++中想做游戏是很难的,但我不这么想,在下写了一些小游戏给客官看看一,2048#include<iostream>#include<vector>#include<ctime>#include<cstdlib>usingnamespacestd;classGame_2048{public:Game_2048();~Game_2048();voidintroduction()......
  • C++万字解析类和对象
     1.类的定义class为定义类的关键字,Stack为类的名字,{}中为类的主体,注意类定义结束时后面分号不能省略。类体中内容称为类的成员:类中的变量称为类的属性或成员变量;类中的函数称为类的方法或者成员函数。为了区分成员变量,一般习惯上成员变量会加一个特殊标识,如成员变量前面......
  • C++入门基础(内容太干,噎住了)
     文章目录1.缺省参数2.函数重载2.1重载条件:1.参数类型不同2.参数个数不同3.参数类型顺序不同 2.2不做重载条件情况:1.返回值相同时2.当全缺省遇见无参数3.引用3.1引用特性:3.2引用的使用1.缺省参数1.缺省参数是声明或定义函数时为函数的参数指定⼀个缺省值。......
  • C++ 模板类类型限定
    #include<iostream>#include<type_traits>usingnamespacestd;namespace{classIAnimal{public:virtualvoidsay()=0;};classDog:IAnimal{public:voidsay()override{......
  • C++中深拷贝与浅拷贝
    描述:在未定义显示拷贝构造函数的情况下,系统调用默认的拷贝函数——即浅拷贝,它能够完成成员的简单赋值拷贝操作。当数据成员中没有指针时,浅拷贝是可行的;但当数据成员中有指针时,如果采用简单的浅拷贝,则两类中的两个指针将指向同一个地址,当对象快结束时,会调用两次析构函数,执行两......
  • 南沙信C++陈老师解一本通题:1310:【例2.2】车厢重组
    ​【题目描述】在一个旧式的火车站旁边有一座桥,其桥面可以绕河中心的桥墩水平旋转。一个车站的职工发现桥的长度最多能容纳两节车厢,如果将桥旋转180度,则可以把相邻两节车厢的位置交换,用这种方法可以重新排列车厢的顺序。于是他就负责用这座桥将进站的车厢按车厢号从小到大排列......
  • C++字符串中的string类操作
    愿我如星君如月,夜夜流光相皎洁。                           ——《车逍遥篇》【宋】范成大目录正文:主要特点:基本操作: 代码演示:总结:今天我们接着上次的章节继续,这次我们来说一个为解决上个方法的缺陷而诞生......
  • 大二上 C++高级程序设计笔记(1) 栈和c++对c的补充 20240908
    Q1:什么是static类的储存变量?A1:在C++中,static关键字可以用于类成员变量和成员函数,以改变其作用域和生命周期。当static用于类的成员变量时,它具有以下特性:全局唯一性:静态成员变量不属于任何特定的对象实例,而是属于类本身。这意味着无论创建多少个类的对象,静态成员变量都只有......
  • 【C++ Primer Plus习题】12.6
    1大家好,这里是国中之林!❥前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看←问题:解答:main.cpp#include<iostream>#include<cstdlib>#include<ctime>#include"queue.h"using......