1.关于 #define
的简介:
需要注意的是#define PI 3.14159
发生作用在预处理阶段,在编译阶段之前,也就是说在预处理阶段,预处理器会进行文本替换 ,把所有非字符串形式的PI
都替换为 3.14159
。 常见的关于 #define
的用法,以下是使用 #define
定义一个常量或者函数:
·定义常量: #define PI 3.14159
·定义函数: #define Sum(a,b) a*b*a*b*a*b*a*a*b
2. #define
的优缺点:
但是,使用以上的两种常用的方式,会有相应的缺点和优点:
关于:#define PI 3.14159
优点:
- 不需用在所有需用使用到常量
3.14159
的地方书写数字,避免粗心输入错误的问题,可以使用宏更好的见名知意。
缺点:
- 正如上面描述,因为宏替换发生在预处理阶段,是预处理器在负责,所以编译器看不到
PI
,所以如果常量3.14159
在编译阶段报错,报的错会提示3.14159
的错误,而不是PI
的问题,从而你无法定位具体错误在哪里,得思考3.14159
是什么,再极端点,这个PI
定义在一个不是你写的头文件里面,那就更加麻烦了。 - 无法提供作用域(除非使用
#undef
)。
关于: #define Sum(a,b) a*b*a*b*a*b*a*a*b
- 优点:
- 节约函数调用的时间,所有使用
Sum
函数的地方,都进行了宏替换 - 使用方便
- 节约函数调用的时间,所有使用
- 缺点:
- 单纯的文本替换,在所有使用宏的地方都会出现的
a*b*a*b*a*b*a*a*b
副本,假如函数体很长,十分不可行 - 实参括号容易出错
- 无法提供作用域(除非使用
#undef
)
- 单纯的文本替换,在所有使用宏的地方都会出现的
3.关于#define PI 3.14159
缺点的处理方式
#define PI 3.14159
建议替换为如下形式:
const double pi = 3.14159; //大写是宏的命名方式
或:
class Stu
{
private:
static const double pi = 3.14159; //这种方式把pi的作用域限制在了class内,且pi只有一份实体
};
或:
class Stu
{
private:
enum{Num = 3}; //这种方式理论基础:"一个属于枚举类型的数值,可权充ints被使用"
//还有个好处,这种方式可以让你避免Num被取地址
int size[Num];
};
4.关于#define Sum(a,b) a*b*a*b*a*b*a*a*b
缺点的处理方式
#define Sum(a,b) a*b*a*b*a*b*a*a*b
建议替换为内联函数:
inline int Sum(int a,int b)
{
return a*b*a*b*a*b*a*a*b; //使用inline函数提高效率
}
或使用函数模板:
template<typename T>
inline T Sum(const T &a,const T &b)
{
return a*b*a*b*a*b*a*a*b; //使用函数模板来满足宏的类型匹配问题
}
5.const为什么不会导致重复定义问题?
当在C++中定义全局变量时,如果多个源文件包含了同一个头文件,并且该头文件中定义了全局变量,将会导致重复定义的错误。然而,对于 const 修饰的全局变量,它们在默认情况下具有内部链接(internal linkage),因此不会导致重复定义的错误。
内部链接意味着 const 变量只在定义它的源文件中可见,其他源文件无法访问它。当多个源文件包含同一个头文件时,每个源文件会独立拥有自己的 const 变量副本,而这些副本在不同的源文件中是相互独立的。
这种行为是因为编译器将具有 const 修饰的全局变量视为只读常量,因此对于每个源文件来说,它们并不需要在链接阶段合并为一个定义。相反,编译器将在每个源文件中生成自己的 const 变量,这些变量在链接时不会发生冲突。
需要注意的是,如果在全局变量定义时使用了 extern 关键字,它将不再具有内部链接,并且会导致重复定义的错误。例如:
// header.h
extern const int a;
// source1.cpp
#include "header.h"
const int a = 10;
// source2.cpp
#include "header.h"
const int a = 20; // 重复定义错误!
在上述示例中,使用 extern 关键字声明了 a,表示它在其他源文件中定义。然而,由于头文件中的 a 并没有具体的定义,因此每个源文件会生成自己的 a 定义,最终导致重复定义的错误。
综上所述,对于使用 const 修饰的全局变量,默认情况下具有内部链接,每个源文件都会生成自己的副本,不会导致重复定义的错误。而对于带有 extern 关键字的全局变量,需要在某个源文件中进行实际的定义,然后在其他源文件中进行声明以避免重复定义的错误。