C++ 宏(define)

宏的概念

宏的概念:使用宏的位置,在预处理阶段只是进行了“字符替换”,被“字符”替换的宏就成为了代码的一部分,看下面这个代码你就明白了“被“字符”替换的宏就成为了代码的一部分”是什么意思:

// test.cpp
#include <iostream>
#define TEST_INT_8 int a=8
using namespace std;

int main(void)
{
        TEST_INT_8;

        cout<<a<<endl;
        return 0;
}

使用g++处理test.cpp:

g++ -E test.cpp -o test.i

预处理后test.i中可以看到main函数的内容变为了:

int main(void)
{
 int a=8;

 cout<<a<<endl;
 return 0;
}

可以看到TEST_INT_8的作用和直接写int a=8d的作用一样的,这就是我说的:“被“字符”替换的宏就成为了代码的一部分”

再比如下面这个例子也充分体现了“被“字符”替换的宏就成为了代码的一部分”这一个概念。

#include <iostream>
#include <stdexcept>
#include<bitset>
#define CheckBuffer(x) { if ((nBufSize-nOffset)<(x)) { nUsedLen = nOffset; return 0;} } 

using namespace std;

int main(void)
{
    int nBufSize=1;
    int nOffset=1;
    int nUsedLen =1;
    CheckBuffer(9);  // 上面三个局部变量会传进宏CheckBuffer中。
    return 0;
}

宏定义中的特殊操作符

define 中的特殊操作符有#,##和… and __VA_ARGS__(参考自:c/c++中define用法详解及代码示例):

  • #:将宏参数替换成字符串。如果x是一个宏参量,那么#x可以把参数名转化成相应的字符串:
#incldue <stdio.h>  
#define PSQR(x) printf("the square of" #x "is %d.\n",(x)*(x)) // 第一个x被替换成字符串,
                                                              // 后面两个x表达代码中应表达的函数
int main(void)
{
    int y =4;
    PSQR(y);
    //输出:the square of y is 16.
    PSQR(2+4);
    //输出:the square of 2+4 is 36.
    return 0;
}
  • ##:这个运算符把两个语言符号组合成单个语言符号。
#include <stdio.h>
#define XNAME(n) x##n
#define PXN(n) printf("x"#n" = %d\n",x##n)
int main(void)
{
    int XNAME(1)=12;//int x1=12;
    PXN(1);//printf("x1 = %d\n", x1);
    //输出:x1=12
    return 0;
}
  • __VA_ARGS__ 是一个可变参数的宏,很少人知道这个宏,这个可变参数的宏是新的C99规范中新增的,目前似乎只有gcc支持(VC6.0的编译器不支持)。
    实现思想就是宏定义中参数列表的最后一个参数为省略号(也就是三个点)。这样预定义宏__VA_ARGS__就可以被用在替换部分中,替换省略号所代表的字符串。
#define PR(...) printf(__VA_ARGS__)
int main()
{
    int wt=1,sp=2;
    PR("hello\n");
    //输出:hello
    PR("weight = %d, shipping = %d",wt,sp);
    //输出:weight = 1, shipping = 2
    return 0;
}

省略号只能代替最后面的宏参数。
#define W(x,…,y)错误!
但是支持#define W(x, …),此时传入的参数个数必须能够匹配。

这里再介绍几个系统的宏:

  1. __FILE__ 宏在预编译时会替换成当前的源文件名
  2. __LINE__宏在预编译时会替换成当前的行号
  3. __FUNCTION__宏在预编译时会替换成当前的函数名称

宏的其他应用

c/c++中define用法详解及代码示例中提到的应用:

  • 宏的多行定义时,行尾要加“\”,不是本博客中提到的“/”
  • “#ifdef和#define”来实现不同的平台使用不同的代码。
  • 取消宏:#undef
  • 防止重复包含头文件

宏与其他具有替换作用的关键字的区别

宏与其他具有替换作用的关键字的区别是:宏替换是在预处理阶段,宏只是起到了简单的替换作用,而其他具有替换作用的关键字一般都各有各的特点。所以说区别的时候,只要讲define只是简单地替换作用,然后讲一下其他具有替换作用的关键字的特点就行。

1.宏定义表示数据类型和用typedef定义数据说明符的区别:
宏定义只是简单的字符串代换,是在预处理完成的,而typedef是在编译时处理的,它不是作简单的代换,而是对类型说明符重新命名。

#define PIN1 int *
typedef (int *) PIN2;

PIN1 a,b;  // 在宏代换后变成:int *a,b;
PIN2 c,d;

a是指向整型的指针变量,而b是整型变量。c,d都是指向整型的指针变量。

2.inline和define区别

  • 处理阶段:宏定义define在预处理阶段就换成了字符串的替换,而inline在编译阶段进行。

  • 类型安全检查:宏定义define是简单的字符串替换,不存在类型安全检查,而inline函数还是一个函数,编译器会进行类型安全检查,因此inline更加安全。

  • 替换方式:宏定义define只是单纯的字符串替换,而inline是代码嵌入,也就是说编译器在函数调用的地方直接将inline函数代码写进去,这样就不会产生函数的调用跳转(无栈帧消耗),因此适用于短小的函数,并且安全可靠。

  • 使用方式:宏定义define只要定义了就会替换,而inline只是建议,编译器可以拒绝替换,在函数较大的时候,编译器可以选择不展开相应的函数。

3.宏定义和全局变量的区别(参考自:链接

  1. 宏会在预处理阶段被替换,而全局变量是在运行时;
  2. 宏定义不分配内存,全局变量定义需要分配内存;
  3. 宏不区分数据类型,它本质上是一段字符,在预处理的时候被替换到引用的位置,而全局变量区分数据类型;
  4. 宏定义之后值是不能改变的,全局变量的值是可以改变的;
  5. 宏定义只有在定义所在文件,或引用所在文件的其它文件中使用。 而全局变量可以在工程所有文件中使用,只需在使用前加一个声明。
posted @ 2022-07-24 20:06  好人~  阅读(407)  评论(0编辑  收藏  举报