• C语言:对于宏的一些概念及技巧


    一、前言

      宏在C语言中是一段有名称的代码段,在程序编译过程中,会将宏的内容被这段代码进行替换,常常用于定义一些常量、函数、代码块等,由于近年来发现许多公司进行面试时对于宏的面试题尤为多,故本文将对C语言中的宏的结构、使用以及注意事项进行详细介绍,有想法的小伙伴还可以在此基础上继续深入研究。

    二、宏的基本结构

    宏的基本结构如下:

    在这里插入图片描述

    例如:
    #define  PI   3.1415         
    #define  number  50         
    #define  MAX(x , y ) ((x)>(y)?(x):(y)) 
    
    • 1
    • 2
    • 3

    三、宏的基本使用

    1、不携带参数的宏的定义
    格式:
    #define   宏名     表达式
    例如:
    #define    PI    3.1415  //程序在预处理阶段会将PI替换为3.1415
    
    • 1
    • 2
    • 3
    • 4
    注意事项:
    1)宏定义实质只进行替换,不进行计算
    (2)宏名之后的表达式可以是常数、条件语句、函数等,预处理程序对它不做任何检查,程序在编译时才对宏替换的内容进行检查
    (3)宏定义不是说明或语句,在行末不需要添加分号,如果用户在行末添加分号,则连分号一起进行替换
    例如:
    #define   PI   3.1415   //将PI替换为“3.1415”
    #define   PI   3.1415;   //将PI替换为“3.1415;”4)宏定义存在于全局,其作用域为全局作用域
    例如:
    xxx.c:
    #include “stdio.h”
    #include “stdlib.h”
    #define  PI   3.1415   //该宏存在于全局
    int main()
    {
    printf(“PI=%f\n”,PI);
    }5)宏定义允许发生嵌套,即一个宏可以使用另外一个已经存在的宏
    格式:
    #define   number   50 ;  
    #define   sum      number*50  ; //宏的嵌套,将number替换成50,将sum替换成number*50
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    2、携带参数的宏的定义
    定义:
    #define    宏名(参数1,参数2.....)    表达式
    调用:
    宏名(实参1,实参2...........)
    
    例如:
    定义:
    #define   getMax(a,b)  a>b?a:b  //将getMax(a,b)替换成a>b?a:b的结果
    调用:
    int  num=getMax(10,20)  ;//调用之后getMax(10,20)返回最大值20
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    注意事项:

    (1)考虑优先级问题,即如果宏定义中的表达式涉及运算符的优先级问题,需要用户及时考虑

    第一种:考虑表达式中涉及优先级问题

    例如:

    代码如下:
    #define   getSum(a,b)   a*b   
    int  result1=getSum(40,20) ;
    int  result2 =getSum(10+30,20);
    
    • 1
    • 2
    • 3
    • 4

    运行结果如下:

    通过上面代码发现,最终计算的结果不一致,下面来分析一下原因:

    1#define   getSum(a,b)   a*b
    int  result1=getSum(40,20) ; //目标是计算40*20的结果,编译器在执行时,将a替换为40,将b替换为20,故a*b的值为40*20,即800
    
    • 1
    • 2
    • 3
    2#define   getSum(a,b)   a*b
    int  result2 =getSum(10+30,20);//目标是计算(10+30)*20的结果,但是编译器在执行时,将a替换为10+30,将b替换为20,这时候a*b的值为10+30*20,即考虑优先级先执行乘法运算,再执行加法运算,所以结果为610
    
    • 1
    • 2
    • 3
    总结:
      通过以上1)和2)两点,我们如何进行修改才能达到最初的目标40*20=800的结果?
    修改如下:
    代码:
    #define    getMax(a,b)    (a) *b
    int result1=getMax(10+30,20)  //计算结果:(10+30)*20=800
    int result2=getMax(40,20)     //计算结果:(40)*20=800
    
    • 1
    • 2
    • 3
    • 4
    运算结果:

    在这里插入图片描述

    第二种:考虑宏替换返回结果后涉及优先级问题

    例如:
    代码:
    #define   getSum(a,b)   a+b   
    int  result1=getSum(40,20)*3 ;//目标是计算(40+20)*3=180
    
    • 1
    • 2
    • 3
    运算结果:

    在这里插入图片描述

    通过上面代码发现,最终计算的结果是100,而不是180,下面来分析一下原因:
    #define   getSum(a,b)   a+b   
    int  result1=getSum(40,20)*3 ;//编译器在执行时,将a替换为40,将b替换为20,这时候result1=40+20*3,即先执行20*3=60,再执行40+60=100
    
    • 1
    • 2
    • 3
    总结:

      通过上面代码,我们如何实现最初的目标(40+20)*3=180?

    修改如下:
    #define    getSum(a,b)   (a+b)
    int result1=getSum(40,20)*3  //计算结果:(40+20)*3=180
    
    • 1
    • 2
    运行结果:

    在这里插入图片描述
    (2)带参数的宏与函数的区别
    1)宏比函数的运算速度快

    使用宏:

    在这里插入图片描述

    使用函数:

    在这里插入图片描述
    2)宏不需要执行形参类型,而函数需要指定形参类型

    例如:
    宏:
    #define  getMax(a,b)   a>b?a:b   //a和b没有指定类型
    函数:
    void function(int a, int b);          //a和b需要指定类型
    
    • 1
    • 2
    • 3
    • 4
    • 5

    3)宏不能够进行调试(因为宏替换工作是在预处理阶段)
    4)宏不能实现递归
    5)预处理符号“#”,如果设置一个表示将宏参数转为字符串,也通常被称为字符串转化运算符;如果设置两个表示将两个宏参数进行连接,称为连接运算符

    一个“#”格式:
    #define   get_Str(x)    #x       //参数x将转换为字符串进行输出
    
    • 1
    • 2

    在这里插入图片描述

    两个“#”格式:
    #define    get_str(a,b)    a##b    //将参数a和b进行连接后返回
    
    • 1
    • 2

    在这里插入图片描述

  • 相关阅读:
    flask要点与坑
    二叉树MFC实现
    膀胱癌、炎症和微生物组
    Kubernetes(29):Kubernetes Dashboard的使用
    【Python】基础练习题_ 函数和代码复用
    吃透负载均衡
    十一月组队学习报名啦!
    Maven 是什么?为什么要学习Maven?
    学了C++能做什么?
    认证授权与JWT
  • 原文地址:https://blog.csdn.net/Mr_zhang1911116/article/details/134272355