C/C++预处理器,宏定义,宏函数浅析

预处理器简介

预处理器不是编译器的组成部分,他是编一过程中的一步,发生在编译之前。我们把C预处理器(C Preprocessor)简称为CPP。预处理的作用就是在代码被编译前对代码做某些替换。

指令规则

  1. 预处理指令的写法都是以#开头,#必须是该行第一个非空白字符,#和关键字之间允许存在任意个数的空白字符,接着是指令所需要的其他信息,整行够成了一条预处理指令。
  2. 预处理指令总是在第一个换行符结束,除非明确的指明指令要继续。
  3. 预处理指令可以出现在文件的任何地方。通常我们将#define和#include指令放在文件的开始。

预编译指令

在这里插入图片描述
上面指令大多通过关键就能理解其意义,所以就不一一举例说明了。

预定义宏

在这里插入图片描述
注:
预定义宏中所有的宏定义左右均是两个下划线

预处理器运算符

宏延续运算符\
如果宏太长,写在一行容纳不下那么就可以使用“\”表示在下一行写的内容和本行有同样的效果,表示下一行是上一行的延续,下面上代码:

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

上面两种写法作用相同。
字符串常量化运算符#

#define MY_PRINTF(x,y) printf(""#x"=%d,"#y"=%d\n",x,y);
int main(){
    int a=10,b=20;
    MY_PRINTF(a,b);//相当于printf("a=%d,b=%d\n",a,b);
}
输出为:
a=10,b=20

上面代码在printf第一个参数中添加宏定义的参数必须用#才能将参数引用进去否则会报错,因为printf的第一个参数中全是常量如果不用#将参数变成常量就会报错。
标记粘贴运算符##

#define MY_PRINTF(x,y) (x##y##cd)
int main(){
    int a=10,b=20;
    int abcd=1000;
    std::cout<<MY_PRINTF(a,b)<<std::endl;//相当于达因变量abcd
}
输出为:
1000

上面代码可以看出##的作用是拼接。代码中定义了变量abcd,在宏定义时采用x##y##cd的方式拼接了变量abcd,这里取的是变量的名字拼接而不是他的值拼接。

defined()运算符
该运算符是确定某个标识符在此之前是否使用#define 定义过,如果定义过则为真否则为假。

#define PI 3.14
int main(){
#if defined(PI)
    std::cout<<"defined"<<std::endl;
#else
    std::cout<<"no define"<<std::endl;
#endif
}
输出为:
defined

宏定义注意事项

在定义一些运算比较等方面的宏时需要加括号以免一些运算符的优先级对宏最后结果的影响。比如下面代码:

#define A(a,b) a*b
int main(){
    std::cout<<A(2+2,2+2)<<std::endl;
}
输出为:
8

上面代码是想定义一个宏来算两个参数的乘积,但是因为没有加括号变成了运算2+2*2+2,这并不是我们想要的结果。下面这么写才是我们预期的结果。

#define A(a,b) ((a)*(b))
int main(){
    std::cout<<A(2+2,2+2)<<std::endl;
}
输出为:
16

宏定义进阶-宏函数

上面的一些例子都是定义的比较简单的宏,即使带参数的宏也没有涉及到循环等相对复杂的。下面我们就将一个函数翻译成一个宏,用宏函数来代替函数。下面我们实现一个函数该函数功能为将一个数每次增加1循环5次将结果返回。
普通函数实现:

int fun(int k)
{
    for(int i=0;i<5;++i)
    {
        k++;
    }
    return k;
}
int main(int argc, char *argv[])
{
    int a=10;
    std::cout<<fun(a)<<std::endl;
}

下面宏函数实现:

#ifndef FUN
#define FUN(K)  ({\
    for(int i=0; i<5; ++i)\
    { \
        K++; \
    } \
    K;})         //如果这个地方增加换行符号 "\" #endif上方一定要有一个空行不然编译会报错,因为#endif没有单独占一行 
#endif
int main(int argc, char *argv[])
{
    int a=10,b=0;
    b = FUN(a);
    std::cout<<b<<std::endl;
}

注意

  1. 宏函数的返回值是通过变量,没有return语句,因为宏函数就是宏替换到了函数里,除非你想将调用宏函数的函数直接返回可以使用return
  2. 宏函数独占一行,如果宏函数比较复杂需要使用换行符""
  3. 如果宏函数中单独写一个if判断,在调用宏函数的函数中存在if,elseif,else等语句需要注意为宏函数整体增加大括号将宏函数中的if作用范围限定住,否者会出现if,else混乱的问题
  4. 宏函数常使用do while语句通过break进行跳转

以上就是我对宏函数的一些理解


版权声明:本文为qq_33865609原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
THE END
< <上一篇
下一篇>>