(C++)为什么要尽量避免使用#define?
(第一次写博客,不好请见谅。知识点是从《C++编程语言99个常见编程错误》里看的)
#define 是C++中的一个为常量定义名称的预处理命令。一般情况下,其实并没有道理一定要使用#define,因为其总能带来一些麻烦。这篇博客主要是列举该命令的弊端,并讲述其他代替方案。
(有的从C转行C++的可能会建议你使用它,但是这里是C++,不是C)
1. define 定义字面值常量的弊端:
第一:作用域问题
#define PI 3.1415926
PI没有作用域,所以可能出现这种情况:
//File: MathLibrary.hpp
//其他的一些代码...
#define PI 3.1415926
//还是其他的代码...
然后我们在一个程序里面使用这个库:
#include "MathLibrary.hpp"
//其他代码...
double aFunction(double Length)//返回半径为 Length 的圆的面积(懒得想名字了)
{
const auto PI = 3.14;//PI不存在作用域,所以这行代码等价于 const auto 3.1415926 = 3.14;
//而3.1415926是个右值,不能用于声明 & 定义。
//其他的代码...
}
第二:地址问题
#define NUMBER 233
int* aPointer = &NUMBER;//&NUMBER 被预处理器改成 &233 ,而233是个右值,没有地址。
第三:括号问题
#define MY_NUMBER 1<<5
int aNewNumber = MY_NUMBER * 2;//多半是废物:预处理器把表达式改为1<<5 * 2,即1 << (5 * 2)
第四:数据类型问题
这个就不写代码了。
宏本来就没有数据类型。一般情况下没啥事发生,但是遇到函数重载就麻烦了(数据类型作为函数签名的一部分)。
第五:记号问题
const int NUMBER = 233;
假设我们使用NUMBER,结果用错了,编译器就会提示NUMBER使用错误。(傻子都知道)
但是#define呢?预处理器比编译器快一步处理代码,所以如果我们用#define,那么报错时编译器不可能见到NUMBER,只能见到233,所以编译器只会说233使用错误。如果NUMBER被封装,那么用户压根不知道233是啥,只能一脸懵逼。
/*==========分割线==========*/
上述就是用#define定义字面值常量的问题。
一般情况,我们可以用const来定义字面值常量。如果担心资源占用,可以用enum枚举。
2. 用#define定义伪函数的弊端:
第一:运算符优先级问题
#define YES_OR_NO(NUM) NUM ? "Yes" : "No" //忘记加括号了
std::cout << YES_OR_NO(n) << std::endl;//该语句被视为std::cout<< n ? "Yes" : "No" << std::endl;
//即(std::cout<< n) ? "Yes" : ("No" << std::endl);
关键是这段代码一直报错,你却不知道有什么问题,因为一切都是如此完美。
第二:先替换,再运算
#include<iostream>
using namespace std;
#define OUT(N) (cout << (N) << ' ' << (N) << ' ' <<(N) <<endl)
int main()
{
int a = 0;
OUT(a);//注意
}
//第五行代码等于
(cout << (a++) << ' ' << (a++) << ' ' <<(a++) <<endl)
a自增了3次。
第三:作用域操作问题
int age = 0;
#define YOUR_BIRTHDAY() (age++) //每次调用,age+1
int main()
{
Age age(Dogs);//狗的年龄
YOUR_BIRTHDAY(); //因为作用域,你的年龄变量被遮盖,所以最后狗的年龄自增了
}
/*==========分割线==========*/
所以,伪函数一般都没啥用(但有时候还是有点用的,比如代码涉及到__LINE__等预处理器指令时)。
一般建议使用inline代替#define,效率照样高。
总结
珍爱生命,远离#define。
(有错误在评论区指正。有问题欢迎提问,特别难的除外)
本文详细阐述了在C++编程中应避免使用#define的原因,包括作用域、地址、括号、数据类型及记号等问题,同时提出了const和inline作为替代方案。
3314

被折叠的 条评论
为什么被折叠?



