#define 的使用
#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 的使用相关推荐
- 非本地类型不能定义方法 cannot define new methods on non-local type time.Duration
能够随意地为各种类型起名字,是否意味着可以在自己包里为这些类型任意添加方法 ? 参见下面的代码演示 : package mainimport "time"type MyDurati ...
- C++ 笔记(32)— 预处理、文件包含include、宏替换define、条件包含ifndef、define
C/C++预处理器在源代码编译之前对其进行一些文本性质的操作. 它的主要任务包括删除注释 . 插入 #include 指令包含的文件的内容 . 定义和替换由 #defme 指令定义的符号以及确定代码的 ...
- C++ #define(宏定义)的使用
C++ 宏定义 #define命令是C++语言中的一个宏定义命令,它用来将一个标识符定义为一个字符串,该标识符被称为宏名,被定义的字符串称为替换文本. 宏定义的一般形式 #define <宏名& ...
- C++ 笔记(07)— 常量(字面常量、const定义常量、constexpr 定义常量、enum 定义常量、define 定义常量)
在 C++ 中,常量类似于变量,只是不能修改.与变量一样,常量也占用内存空间,并使用名称标识为其预留的空间的地址,但不能覆盖该空间的内容. 常量可以是任何的基本数据类型,可分为整型数字.浮点数字.字符 ...
- const与define相比优点_const与#define的区别、优点
const与#define的区别 编译器处理方式不同 define宏是在预处理阶段展开. 补充:预处理器根据以#开头的命令,修改原始的程序.比如我们常见的#include 命令告诉处理器读取系统头文件 ...
- define的多行定义
在软件开发过程中,经常有一些常用或者通用的功能或者代码段,这些功能既可以写成函数,也可以封装成为宏定义.那么究竟是用函数好,还是宏定义好?这就要求我们对二者进行合理的取舍. 宏定义中允许包含两行以上命 ...
- C++中typedef和define的区别
typedef和#define的用法与区别 一.typedef的用法 在C/C++语言中,typedef常用来定义一个标识符及关键字的别名,它是语言编译过程的一部分,但它并不实际分配内存空间,实例像: ...
- c 宏定义用法#define
转自:https://blog.csdn.net/boring_wednesday/article/details/78756696 宏定义 语法 #define name Stuff #de ...
- typedef和define具体的详细区别
1) #define是预处理指令,在编译预处理时进行简单的替换,不作正确性检查,不关含义是否正确照样带入,只有在编译已被展开的源程序时才会发现可能的错误并报错.例如: #define PI 3.141 ...
- 深度分析define预处理指令
#define语句 预处理 宏替换 --以上出自<C语言入门经典(第四版)> #和## --出自<C语言程序设计:现代方法(第2版)> #undef取消定义 --以上出自< ...
最新文章
- 浏览器的加载与页面性能优化
- Linux文件夹分析
- java return用法_Java枚举的高级用法之多键值的映射使用
- [WebApp]定宽网页设计下,固定宽度布局开发WebApp并实现多终端下WebApp布局自适应...
- [NodeJS] 优缺点及适用场景讨论 - 鱼松
- 自己服务器上部署APP应用(安卓和IOS版),下载页面的代码,以及IOS的xxx.plist文件的建立
- Windows环境下32位汇编程序设计C版code--第五章(一)
- ArcGIS Engine 10 开发常见问题的解决方法
- MetaException(message:Hive Schema version 3.0.0 does not match metastore's schema version 1.2.0 Meta
- [Java基础]体验Lambda表达式
- HDU4612 Warm up
- 单片机sleep函数的头文件_单片机空项目代码解析
- tesseract-ocr 识别中文扫描图片
- 【Java企业级开发二】jsp简答题汇总
- mysql游标嵌套怎么写,mysql游标和嵌套游标
- ThinkPHP5分页样式
- 数据管理平台(DMP)
- 你愿意做高学历却抑郁的人,还是低学历开心的人?(持续更新中)
- 赋诗一首!——《秋》
- 如何创建一个微信公众号(手把手、超详细)