#define 多数情况下我们是用来定义宏的,但是实际上,#define 作为预处理指令,也可以用来定义标识符,类似于 typedef,但是其本质和 typedef 是不同的。


目录

一、#define 定义标识符

1、定义和使用

2、#define 定义标识符 和 typedef 定义别名的区别

二、#define 定义宏

1、无参​​​​​​​

2、有参

3、宏和函数的比较

(1) 宏的优点

(2) 宏的缺点


一、#define 定义标识符

1、定义和使用

#define 的本质是替换,将前者替换为后者,比如如果代码中使用了 reg,在预处理阶段,reg 就会被替换为register。

#define reg register          //为 register这个关键字,创建一个简短的名字#define do_forever for(;;)     //用更形象的符号来替换一种实现#define CASE break;case        //在写case语句的时候自动把 break写上。// 如果定义的 stuff过长,可以分成几行写,除了最后一行外,每行的后面都加一个反斜杠(续行符)。
#define DEBUG_PRINT printf("file:%s\tline:%d\t \date:%s\ttime:%s\n" ,\__FILE__,__LINE__ ,       \__DATE__,__TIME__ )  

2、#define 定义标识符 和 typedef 定义别名的区别

以下面这个例子为例,p1、p2、p3、p4分别是什么类型??

#define ptr_t int*
typedef int* ptr_t2;int main() {ptr_t p1, p2;ptr_t2 p3, p4;return 0;
}

宏的本质是替换,预处理阶段会被替换成如下状态。此时 * 会优先和离自己近的变量名结合,因此p1 是 int* 型指针,而 p2 是普通的 int 型变量。

int* p1, p2;    //int *p1, p2;

但是typedef 是起一个别名,即便是换成了ptr_t2 ,ptr_t2不会替换,而是一种实打实的类型,此时p3、p4都是 int* 型,因此,p3、p4都是int* 型指针。

二、#define 定义宏

根据有无参数列表,宏的定义方式可以分为无参和有参。

1、无参

(1) 定义

无参的声明可以参考下面的例子。宏的本质是替换,所以宏是

#define reg register   // 定义标识符
#define MAX 100        // MAX 是宏的名字,100 是 MAX 对应的值

(2) 使用

#define MAX 100
int main(){int a = MAX;    // 预处理阶段,这行代码会变成 int a = 100;return 0;
}

注意 :宏的本质是替换,在预处理阶段,宏的名字会被替换成对应的值,因此在声明宏的时候不能出现分号 ';',如果出现了分号就变成下面这样

2、有参

有参就涉及到参数传递了,此时需要记住:传递参数的时候,表达式不参与任何运算。宏的本质依然是替换,此时的步骤是:先传参,后替换

(1) 定义

就像函数一样,宏会接收传递给自己的参数,但是本质是不一样的

#define ADD(X,Y) X+Y            // 不推荐,这样做只是方便理解,建议带小括号
//#define ADD(X,Y) ((X) + (Y))    // 推荐

(2) 使用

#define ADD(X,Y) X+Yint main() {int a = ADD(10, 20);    // 就像调用函数一样,会进行参数传递// 但本质是替换,预处理阶段会被替换成// int a = 10 + 20;return 0;
}

注意:宏的本质是替换,即便有参数,也是先传递参数,再进行替换

(3) 宏存在参数传递时的注意事项

在定义的时候也提到了,表达式的每个变量建议加上小括号。以下面这个例子为例,本来的目的是求一个数的平方,但是实际上的结果并非如此。

#define SQUARE(X) X*X    // 求平方int main() {int a = 5;int b = SQUARE(a + 1);printf("%d\n", b);return 0;
}

宏存在参数传递的时候,表达式不会参与任何运算,所以这里是直接把 5 + 1 传递给了宏

然后是替换,此时原本的宏就会被替换为

最终得到的结果是 11,为了避免这样的情况,当宏存在表达式的计算时,表达式的每一项建立带上小括号,就像下面这样

#define SQUARE(X) ((X)*(X))    // 求平方

3、宏和函数的比较

宏通常被应用于执行简单的运算。函数可以参数传递,宏也可以参数传递,那么两者有什么区别呢?

(1) 宏的优点

a. 程序规模和调用速度

宏在预处理阶段就被处理了,但是函数要先经过编译、汇编等过程生成符号表才能用于后续的调用,而且函数需要有函数名、函数体。如果仅仅只是简单的功能实现,无论是调用速度还是程序规模,宏都是更胜一筹。

比如获取两个数的较大值:

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

b. 宏与类型无关

函数参数必须要声明指定类型,在没有泛型的情况下,不同类型的处理可能需要定义多个函数,但是宏与类型无关,以比较大小为例,如果只是整型家族的比较,使用宏就足矣。

(2) 宏的缺点

宏的缺点也比较直接明了:

  • 程序长度不建议太长
  • 宏无法调试
  • 由于与类型无关,使用时不够严谨
  • 存在运算符优先级问题(在介绍有参声明的时候提到了)​​​​​​​

#define 的使用相关推荐

  1. 非本地类型不能定义方法 cannot define new methods on non-local type time.Duration

    能够随意地为各种类型起名字,是否意味着可以在自己包里为这些类型任意添加方法 ? 参见下面的代码演示 : package mainimport "time"type MyDurati ...

  2. C++ 笔记(32)— 预处理、文件包含include、宏替换define、条件包含ifndef、define

    C/C++预处理器在源代码编译之前对其进行一些文本性质的操作. 它的主要任务包括删除注释 . 插入 #include 指令包含的文件的内容 . 定义和替换由 #defme 指令定义的符号以及确定代码的 ...

  3. C++ #define(宏定义)的使用

    C++ 宏定义 #define命令是C++语言中的一个宏定义命令,它用来将一个标识符定义为一个字符串,该标识符被称为宏名,被定义的字符串称为替换文本. 宏定义的一般形式 #define <宏名& ...

  4. C++ 笔记(07)— 常量(字面常量、const定义常量、constexpr 定义常量、enum 定义常量、define 定义常量)

    在 C++ 中,常量类似于变量,只是不能修改.与变量一样,常量也占用内存空间,并使用名称标识为其预留的空间的地址,但不能覆盖该空间的内容. 常量可以是任何的基本数据类型,可分为整型数字.浮点数字.字符 ...

  5. const与define相比优点_const与#define的区别、优点

    const与#define的区别 编译器处理方式不同 define宏是在预处理阶段展开. 补充:预处理器根据以#开头的命令,修改原始的程序.比如我们常见的#include 命令告诉处理器读取系统头文件 ...

  6. define的多行定义

    在软件开发过程中,经常有一些常用或者通用的功能或者代码段,这些功能既可以写成函数,也可以封装成为宏定义.那么究竟是用函数好,还是宏定义好?这就要求我们对二者进行合理的取舍. 宏定义中允许包含两行以上命 ...

  7. C++中typedef和define的区别

    typedef和#define的用法与区别 一.typedef的用法 在C/C++语言中,typedef常用来定义一个标识符及关键字的别名,它是语言编译过程的一部分,但它并不实际分配内存空间,实例像: ...

  8. c 宏定义用法#define

    转自:https://blog.csdn.net/boring_wednesday/article/details/78756696 宏定义 语法     #define name Stuff #de ...

  9. typedef和define具体的详细区别

    1) #define是预处理指令,在编译预处理时进行简单的替换,不作正确性检查,不关含义是否正确照样带入,只有在编译已被展开的源程序时才会发现可能的错误并报错.例如: #define PI 3.141 ...

  10. 深度分析define预处理指令

    #define语句 预处理 宏替换 --以上出自<C语言入门经典(第四版)> #和## --出自<C语言程序设计:现代方法(第2版)> #undef取消定义 --以上出自< ...

最新文章

  1. 浏览器的加载与页面性能优化
  2. Linux文件夹分析
  3. java return用法_Java枚举的高级用法之多键值的映射使用
  4. [WebApp]定宽网页设计下,固定宽度布局开发WebApp并实现多终端下WebApp布局自适应...
  5. [NodeJS] 优缺点及适用场景讨论 - 鱼松
  6. 自己服务器上部署APP应用(安卓和IOS版),下载页面的代码,以及IOS的xxx.plist文件的建立
  7. Windows环境下32位汇编程序设计C版code--第五章(一)
  8. ArcGIS Engine 10 开发常见问题的解决方法
  9. MetaException(message:Hive Schema version 3.0.0 does not match metastore's schema version 1.2.0 Meta
  10. [Java基础]体验Lambda表达式
  11. HDU4612 Warm up
  12. 单片机sleep函数的头文件_单片机空项目代码解析
  13. tesseract-ocr 识别中文扫描图片
  14. 【Java企业级开发二】jsp简答题汇总
  15. mysql游标嵌套怎么写,mysql游标和嵌套游标
  16. ThinkPHP5分页样式
  17. 数据管理平台(DMP)
  18. 你愿意做高学历却抑郁的人,还是低学历开心的人?(持续更新中)
  19. 赋诗一首!——《秋》
  20. 如何创建一个微信公众号(手把手、超详细)

热门文章

  1. 网格布局、九宫格布局
  2. 消纳新能源须有“一盘棋”观念
  3. Python爬虫多线程提升数据下载的性能优化
  4. 微信分享到朋友圈java_微信开发(三)微信分享朋友朋友圈
  5. Python Skill - 数据处理-行列互换
  6. CSS3梅花三弄特效
  7. 百无聊赖之JavaEE从入门到放弃(十一)string类 常量池原理 内部类
  8. 爱奇艺AR应用亮相,联合Nreal探索内容新玩法
  9. Webp转成其他图片格式
  10. 一个.NET软件的破解过程