【编译器角度】define
前言
#define 通常用作定义常量
如#define Pi 3.14
甚至替换类型之类的操作#define 整型 int
以至于当时无聊的时候还真有人用define去写中文编程语言
1 |
|
也是能跑的,但是玩归玩
宏定义的名称也与变量名称规则一致,不允许数字开头
正文
正经情况
实际上嘛,常量除了define还有个const
#define定义在头上可能是因为更直观吧,像windows api里面就有一堆#define
1 |
|
c时期define用的多,c++可能更多的用const,但是因为先学c在学c++,所以习惯是潜移默化的。
const定义的好处就是类型检测,限定类型肯定更加严谨。
而#define则相对无脑替换,你可以用它做一些非正常逻辑的事。比如#define true false
,真就是真真假假假假真真。
而且有一种情况下,#define会出事,就是只定义了要替换的名,而不定义要替换成什么。#define x
,你没有东西要替换
1 |
|
要注意不能是int xa,因为这是一个独立的存在,int x a,x才会被宏替换
但是这种在特定情况下有特殊意义:
1 |
|
这种情况下,无非就是像注释一样告诉你这个参数是要输入的。
不过这里值得一提的是jetbrains的软件很早就做了提示形参的功能。
虽然vs2022 在后面版本也支持了类似的功能。
但是这种方法在早期编写的时候的确带来了很大帮助。
undef
之前玩头文件的时候知道防重复除了#pragma once
,还有个#ifdef DEBUG #endif
,表示从define标记的地方开始到结束。
然后这里还有个undef,是表示取消define。
1 |
|
看到当undef掉_Test_
的时候,无法再次使用这个宏。
由于编译特性是自上而下,逐条编译,所以就导致了即使这个undef写在其他函数或者地方,即使没有调用一样也已经删掉这个宏了。
1 |
|
所以说有的是bug都是人为的哈哈哈。。
复杂的宏
简单的常量替换已经没啥问题了,宏还有更厉害的就是可以设计表达式
1 |
这种表达式就比函数又更骚了。但是他不同于函数,函数要入栈,又要入参,又要保持栈平衡。
在预编译的时候就会展开头文件替换所有的宏。
其次在动态开辟的时候,每次都要手动释放delete。那么也同样可以通过宏去干掉。
1 |
|
同样是没问题的。
地址是0是因为nullptr的结果。
换个角度也其实挺像内联的,
# 可以将一个标识符参数字符串化
1 |
|
## 可以连结两个标识符
1 |
|
这样就会生成一个函数
看到两个井号连结在了一起,将x和y当作函数名,然后输出y即可。
实际上肯定也能调用显示:
输出01是因为宏定义的时候输出的y部分,要想输出test也可以输出x即可。
结语
define的骚操作取决于程序员有多骚了可以说是。