LV020-与C不同的const
C++中的 const 和 C 中的 const 是不太一样的,下面就来看一下吧。
在 C 语言中,const 用来限制一个变量,表示这个变量不能被修改,我们通常称这样的变量为常量(Constant)。在 C++中,const 的含义并没有改变,只是对细节进行了一些调整。
一、更像是#define?
先来看下面的两条语句:
const int m = 10;
int n = m;我们知道,变量是要占用内存的,即使被 const 修饰也不例外。m、n 两个变量占用不同的内存,int n = m; 表示将 m 的值赋给 n,这个赋值的过程在 C 和 C++中是有区别的。
在 C 语言中,编译器会先到 m 所在的内存取出一份数据,再将这份数据赋给 n;而在 C++中,编译器会直接将 10 赋给 n,没有读取内存的过程,和 int n = 10; 的效果一样。C++ 中的常量更类似于#define 命令,是一个值替换的过程,只不过#define 是在预处理阶段替换,而常量是在编译阶段替换。
C++ 对 const 的处理少了读取内存的过程,优点是提高了程序执行效率,缺点是不能反映内存的变化,一旦 const 变量被修改,C++ 就不能取得最新的值。如下示例:
#include <stdio.h>
int main()
{
const int n = 10;
int *p = (int *)&n;
printf("n=%d\n", n);
*p = 99; // 修改 const 变量的值
printf("n=%d\n", n);
return 0;
}注意,
&n得到的指针的类型是const int *,必须强制转换为int *后才能赋给 p,否则类型是不兼容的。
将代码放到 .c 文件中,以 C 语言的方式编译,运行结果为 99。再将代码放到 .cpp 文件中,以 C++的方式编译,运行结果就变成了 10。这种差异正是由于 C 和 C++对 const 的处理方式不同造成的。
在 C 语言中,使用 printf 输出 n 时会到内存中获取 n 的值,这个时候 n 所在内存中的数据已经被修改成了 99,所以输出结果也是 99。而在 C++中,printf("%d\n", n); 语句在编译时就将 n 的值替换成了 10,效果和 printf("%d\n", 10); 一样,不管 n 所在的内存如何变化,都不会影响输出结果。
当然,这种修改常量的代码在实际开发中基本不会出现,这里只是为了说明 C 和 C++对 const 的处理方式的差异:C 语言对 const 的处理和普通变量一样,会到内存中读取数据;C++ 对 const 的处理更像是编译时期的 #define,是一个值替换的过程。
Tips:#define 定义的常量仅仅是字符串的替换,不会进行类型检查,而 const 定义的常量是有类型的,编译器会进行类型检查,相对来说比 #define 更安全,所以鼓励使用 const 代替 #define。
二、全局 const 变量的可见范围
1. C 语言中的 const 全局变量
我们知道,普通全局变量的作用域是当前文件,但是在其他文件中也是可见的,使用 extern 声明后就可以使用。
- main.c
#include <stdio.h>
int n = 10;
void func();
int main()
{
func();
printf("main: %d\n", n);
return 0;
}- func.c
#include <stdio.h>
extern int n;
void func()
{
printf("module: %d\n", n);
}编译之后,运行结果如下:
module: 10
main: 10在 C 语言中,const 变量和普通变量一样,在其他源文件中也是可见的。我们可以修改 main.c 如下:
#include <stdio.h>
const int n = 10;
void func();
int main()
{
func();
printf("main: %d\n", n);
return 0;
}修改后的代码仍然能够正确编译,运行结果和上面也是一样的。这说明 C 语言中的 const 变量在多文件编程时的表现和普通变量一样,除了不能修改,没有其他区别。
2. C++中的 const 全局变量
但是如果按照 C++的方式编译(将源文件后缀设置为 .cpp),修改后的代码就是错误的。这是因为 C++ 对 const 的特性做了调整,C++ 规定,全局 const 变量的作用域仍然是当前文件,但是它在其他文件中是不可见的,这和添加了 static 关键字的效果类似。
- main.cpp
#include <stdio.h>
const int n = 10;
void func();
int main()
{
func();
printf("main: %d\n", n);
return 0;
}- func.cpp
#include <stdio.h>
extern int n;
void func()
{
printf("module: %d\n", n);
}虽然 func.cpp 中使用 extern 声明了变量 n,但是在链接时却找不到 main.cpp 中的 n。由于 C++ 中全局 const 变量的可见范围仅限于当前源文件,所以可以将它放在头文件中,这样即使头文件被包含多次也不会出错。
- func.h
const int n = 10;
void func();- func.cpp
#include <iostream>
#include "func.h"
void func()
{
std::cout << "This is func!n=" << n << std::endl;
}- main.cpp
#include <iostream>
#include "func.h"
using namespace std;
int main()
{
func();
cout << "This is main!n=" << n << endl;
return 0;
}3. 总结
C 和 C++中全局 const 变量的作用域相同,都是当前文件,不同的是它们的可见范围:C 语言中 const 全局变量的可见范围是整个程序,在其他文件中使用 extern 声明后就可以使用;而 C++中 const 全局变量的可见范围仅限于当前文件,在其他文件中不可见,所以它可以定义在头文件中,多次引入后也不会出错。