1.使用#define
定义常量
例子
#include <iostream>
#include <string>
using namespace std;#define ARRAY_LENGTH 25
#define PI 3.1415
#define MY_DOUBLE double
#define FAV_WHISKY "Jack"int main() {int number [ARRAY_LENGTH]={0};cout<<"Array's length: "<<sizeof(number)/sizeof(int)<<endl;cout<<"radius"<<endl;MY_DOUBLE radius=0;cin>>radius;cout<<"Area is: "<<PI*radius*radius<<endl;string sky (FAV_WHISKY);cout<<"sky "<<FAV_WHISKY<<endl;system("pause");return 0;
}
PS: 预处理无法知道数据类型,即PI
是3.1415,但不知道是什么类的数据
2.使用宏避免多次包含
多次包含: 是指同一个头文件在编译过程中被包含超过一次,例如,头文件A包含了头文件B,而头文件C也包含了头文件B。如果源文件D同时包含了头文件A和C,那么头文件B实际上被包含了两次。
使用#ifndef
和#endif
来避免
// MyHeader.h#ifndef MY_HEADER_H//查找有没有MY_HEADER_H
#define MY_HEADER_H//没有就定义一个MY_HEADER_H
// 头文件的内容开始
class MyClass {
public:void myFunction();
};
// 头文件的内容结束
#endif // MY_HEADER_H
3.使用#define
定义宏函数
例子
#include <iostream>
#include <string>
using namespace std;#define SQUARE(x) ((x)*(x))//计算平方值
#define PI 3.1415
#define AREA(r) ((PI)*(r)*(r)) //计算圆面积int main() {cout<<"enter x:"<<endl;int num1=0;cin>>num1;cout<<"x*x= "<<SQUARE(num1)<<endl;cout<<"enter radius:"<<endl;int num2=0;cin>>num2;cout<<"Area is "<<AREA(num2)<<endl;system("pause");return 0;
}
PS: 在定义时一定要使用括号,可以让宏代码不受运算符优先级影响
4.使用assert
宏验证表达式
assert宏是断言的一种实现,用于在程序运行时检查某个条件是否为真。如果条件为假,assert宏会终止程序的执行,并通过标准错误输出流输出一条错误消息。
使用assert
需要包含<cassert>
#include <iostream>
#include <cassert>
using namespace std;
int main() {int x = 10;int y = 20;// 验证x是否小于yassert(x < y);// 如果x不小于y,assert宏将触发断言失败,程序将终止执行// 如果x小于y,程序将继续执行cout << "ok" << endl;system("pause");return 0;
}
5.使用宏函数的优点和缺点
优点
①代码复用: 宏允许你定义可复用的代码片段,这些片段可以在多个地方使用,而不需要重复编写。
②简洁性: 宏可以简化复杂的表达式或操作,使代码更加简洁。
③条件编译: 宏可以用于条件编译,允许根据不同的编译条件包含或排除代码段。
④类型无关性: 宏不关心数据类型,因此可以用于多种类型的操作,提供更大的灵活性。
⑤性能: 宏可以用于内联函数,避免函数调用的开销,从而可能提高程序的性能。
⑥跨平台兼容性: 宏可以用来定义跨不同平台或编译器的兼容代码。
缺点
①调试难度: 宏在调试时可能导致困难,因为它们在预处理阶段就进行了替换,这可能会使得调试信息变得混乱。
②类型安全: 宏不进行类型检查,可能会导致类型不安全的错误,特别是在复杂的宏定义中。
③可读性: 过度使用宏可能会降低代码的可读性,特别是当宏在多个文件中被包含时。
④维护性: 宏可能使得代码的维护变得更加困难,因为它们的行为可能不直观,且难以追踪。
⑤优化难度: 由于宏在预处理阶段就进行了替换,编译器的优化器可能无法有效地对使用宏的代码进行优化。
PS: 尽量不要自己编写宏函数