IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 你真的会用宏定义吗?【C语言】 -> 正文阅读

[C++知识库]你真的会用宏定义吗?【C语言】

一句话解释宏定义

所谓宏定义,就是用标识符来表示一些东西,所表示的对象可以是一个数字,也可以是一个字符串,甚至是一段程序。对于#define MAX 100,MAX 就是那个标识符,也称宏名,100 就是替换标识符的内容,也称作宏的定义
在对C源程序预处理时,代码中的所有被宏定义过的标识符都会被替换成它的定义,这个过程叫做"宏替换"或"宏展开"

宏定义详解

  • 简单的宏(对象式宏)#define 标识符 替换列表
    #define MAX 5               
    #define reg register        //为关键字register创造一个别名reg 
    #define do_forever for(;;)  //一个无限循环函数

替换列表可以包括数值常量、字符常量、字符串常量、关键字、标识符和操作符等,当预处理器遇到一个宏定义时,则会将对应替换列表中的内容替换。

  • 带参数的宏(函数式宏)#define 标识符(参数列表) 替换列表
    函数式宏,在展开过程中不仅要进行字符串替换,还要用实参去替换形参
    函数式宏的参数没有限制,可以是类型名、变量名等,因此可以做到函数所不可能的操作,如下面第三个宏定义和#运算符的例子
    #define MAX(x,y) x>y ? x:y               
    #define IS_EVEN(x) ((x)%2 == 0)    
    #define OFFSETOF(StructName, MemberName) (size_t)&(((StructName *)0)->MemberName)   
    //宏定义实现offsetof( )函数,求结构体中某成员的偏移量
    //宏定义的参数为类型名
  • 用于宏定义的一些特殊运算符
    • #运算符
      #运算符将宏的一个参数转换成字符串,仅出现在带参数的宏定义的替换列表中,可以看作给这个参数加上了双引号
      #include<stdio.h>
      #define tostring(c) #c
      #define PRINT(n) printf("The value of "#n" is %d\n", n);
      int main()
      {
          int a = 0, b = 1;
          printf(tostring(a)"\n");
          PRINT(a);       //实际操作的是参数名本身,而不是参数的值
          PRINT(b);
          return 0;
      }
      //out:
      //a
      //The value of a is 0
      //The value of b is 1
      
    • #@运算符
      运算符将宏的一个参数转换成字符,仅出现在带参数的宏定义的替换列表中,可以看作给这个参数加上了单引号
      #include<stdio.h>
      #define tochar(n) #@n
      int main()
      {
          int x = 10;
          printf("%c = %d", tochar(x), x);
      }
      //out:
      //x = 10
      
    • ##运算符
      ##运算符可将两个片段合成一个片段,并进行替换
      #include<stdio.h>
      #define CAT(m, n) m##n 
      int main()
      {
          int num1 = 10;
          printf("%d", CAT(num, 1));
          return 0;
      }
      //out:
      //10
      

宏定义的常见错误使用

  • #include<stdio.h>
    #define ADD1(m, n) m+n
    int main()
    {
        int m = 2, n = 10;
        printf("%d\n", 3 * ADD1(m, n));
        return 0;
    }
    //预计输出:60
    //实际输出:16
    //改正  #define ADD1(m, n) (m+n)
    
  • #define ADD2(m, n) m++; n++;
    int main()
    {
        int m = 1, n = 1;
        if (1) {m--; n--;}
        else ADD2(m, n);
        printf("%d %d\n", m, n);
        return 0;
    }
    //预计输出:0 0
    //实际输出:0 1
    //改正  #define ADD2(m, n) {m++; n++;}
    
  • #define MAX(a, b) ( (a) > (b) ? (a) : (b) )
    int main()
    {
        int x = 5, y = 8;
        int z = MAX(x++,y++);
        printf("%d %d %d\n", x, y, z);
        return 0;
    }
    //预计输出:6 9 8
    //实际输出:6 10 9
    //改正  避免宏定义中使用带副作用的参数
    

这些错误都是因为宏定义只进行了简单的文本替换,程序并没有按照假想的逻辑而执行,不过大部分的错误都能通过规范的编程习惯来避免。
实际开发中,我们很少会使用宏定义去处理复杂的事情。

预定义宏

一些C预先定义完成特定功能的宏

名字定义
__FILE__被编译的文件名
__LINE__文件当前的行号
__DATE__文件被编译的日期
__TIME__文件被编译的时间
__STDC__如果编译器符合C标准,其值为 1

对宏定义的一些说明

  • 宏的本质是进行简单的文本替换,预处理程序对它不作任何检查,如有错误,只能在编译已被宏展开后的源程序时发现,稍不注意可能出现意想不到的错误
  • 宏的替换列表可以包含对其他宏的调用,即宏定义允许嵌套
  • 预处理器只会替换完整的符号,并不会替换宏的片段,也不会替换双引号之内的宏,如:#define MAX 10不会对BUFFER_MAX中的MAX进行替换
  • 宏定义的作用范围通常到出现该宏的文件末尾
  • 宏定义可使用#undef指令取消 #define 标识符
  • 函数式宏与函数
属性函数式宏函数
代码长度每次使用时,宏代码都会被插入到程序中。除了非常小的宏之外,程序的长度会大幅度增长函数代码只出现于一个地方;每次使用这个函数时,都调用那个地方的同一份代码
执行速度相对较快由于存在函数调用与返回,所有可能相对较慢
操作符优先级宏参数的求值是在所有周围表达式的上下文环境里,除非加上括号,否则邻近操作符的优先级可能会产生不可预料的后果,所以建议宏在书写的时候多些括号。函数参数只在函数调用的时候求值一次,它的结果值传递给函数。表达式的求值结果更容易预测
带有副作用的参数参数可能被替换到宏体中的多个位置,所以带有副作用的参数求值可能会产生不可预料的结果。函数参数只在传参的时候求值一次,结果更容易控制
参数类型宏的参数与类型无关,只要对参数的操作合法的,它就可以使用于任何参数类型。函数的参数是与类型有关的,如果参数的类型不同,就需要不同的函数,即使他们执行的任务是不同的。
调试不可调试可调试
递归不可递归可递归

参考书目:《C语言程序设计现代方法 第二版》

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-02-28 15:10:05  更:2022-02-28 15:10:38 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 6:16:48-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码