在C语言中,const  用来限制一个变量,表示这个变量不能被修改,我们通常称这样的变量为常量(Constant)。c语言const的用法

在 C++ 中,const 的含义并没有改变,只是对细节进行了一些调整,以下是最主要的两点。在C++中,const 的含义并没有改变,只是对细节进行了一些调整,以下是最主要的两点。

C++中的 const 更像编译阶段的 #define

先来看下面的两条语句:

1
2
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++ 就不能取得最新的值。

C语言对 const 的处理和普通变量一样,会到内存中读取数据;C++ 对 const 的处理更像是编译时期的#define,是一个值替换的过程。

C++中全局 const 变量的可见范围是当前文件

我们知道,普通全局变量的作用域是当前文件,但是在其他文件中也是可见的,使用extern声明后就可以使用。下面是多文件编程的演示代码:
代码段1(源文件1):

1
2
3
4
5
6
7
8
#include <stdio.h>
int n = 10;
void func();
int main(){
func();
printf("main: %d\n", n);
return 0;
}

代码段2(源文件2):

1
2
3
4
5
#include <stdio.h>
extern int n;
void func(){
printf("module: %d\n", n);
}

不管是以C还是C++的方式编译,运行结果都是:
module: 10
main: 10

在C语言中,const 变量和普通变量一样,在其他源文件中也是可见的。修改代码段1,在 n 的定义前面加 const 限制,如下所示:
const int n = 10;
修改后的代码仍然能够正确编译,运行结果和上面也是一样的。这说明C语言中的 const 变量在多文件编程时的表现和普通变量一样,除了不能修改,没有其他区别。

但是如果按照 C++ 的方式编译(将源文件后缀设置为.cpp),修改后的代码就是错误的。这是因为 C++ 对 const 的特性做了调整,C++ 规定,全局 const 变量的作用域仍然是当前文件,但是它在其他文件中是不可见的,这和添加了static关键字的效果类似。虽然代码段2中使用 extern 声明了变量 n,但是在链接时却找不到代码段1中的 n。

由于 C++ 中全局 const 变量的可见范围仅限于当前源文件,所以可以将它放在头文件中,这样即使头文件被包含多次也不会出错,请看下面的例子。

module.h 代码:

1
2
const int n = 10;
void func();

module.cpp 代码:

1
2
3
4
5
#include <stdio.h>
#include "module.h"
void func(){
printf("module: %d\n", n);
}

main.cpp 代码:

1
2
3
4
5
6
7
#include <stdio.h>
#include "module.h"
int main(){
func();
printf("main: %d\n", n);
return 0;
}

运行结果:
module: 10
main: 10

C和 C++ 中全局 const 变量的作用域相同,都是当前文件,不同的是它们的可见范围:C语言中 const 全局变量的可见范围是整个程序,在其他文件中使用 extern 声明后就可以使用;而C++中 const 全局变量的可见范围仅限于当前文件,在其他文件中不可见,所以它可以定义在头文件中,多次引入后也不会出错。

如果你使用的是 GCC,那么可以通过添加 extern 关键字来增大 C++ 全局 const 变量的可见范围,如下所示:
extern const int n = 10;
这样 n 的可见范围就变成了整个程序,在其他文件中使用 extern 声明后就可以使用了。不过这种方式只适用于 GCC,不适用于 VS/VC。

C++ 中const原理(符号表)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
作者:涛哥
链接:https://zhuanlan.zhihu.com/p/128581278
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

extern const int num;
struct Person
{
int num;
char name[32];
};
void test04()
{
cout<<"全局num = "<<num<<endl;//err 不识别num

//1、c++中 对于基础类型 系统不会给data开辟空间 data放到符号表中
const int data = 10;
//data = 100;//err 只读
cout<<"data = "<<data<<endl;
//2、c++中当 对data 取地址的时候 系统就会给data开辟空间
int *p = (int *)&data;
*p = 2000;
cout<<"*p = "<<*p<<endl;//空间内容修改成功 2000

cout<<"data = "<<data<<endl;//data 还是10为啥?

//2、当以变量的形式 初始化 const修饰的变量 系统会为其开辟空间
int b = 200;
const int a= b;//系统直接为a开辟空间 而不会把a放入符号表中
p = (int *)&a;
*p = 3000;
cout<<"*p = "<<*p <<endl;//3000
cout<<"a = "<<a <<endl;//3000

//3、const 自定义数据类型(结构体、对象) 系统会分配空间
const Person per = {100,"lucy"};
//per.num = 1000;//err
cout<<"num = "<<per.num<<", name = "<<per.name<<endl;//100 lucy
Person *p1 = (Person *)&per;
p1->num = 2000;
cout<<"num = "<<per.num<<", name = "<<per.name<<endl;//2000 lucy
}

c++ 的const符号表总结:

  1. const int data = 10;//data先放入符号表
  2. 如果对data取地址 系统才会给data开辟空间
  3. const int a = b;//b是变量名 系统直接给a开辟空间 而不放入符号表
  4. cosnt 修饰自定义数据 系统为自定义数据开辟空间

参考

  1. https://www.zhihu.com/collection/331097431
  2. https://blog.csdn.net/guonengneng/article/details/88564613?utm_medium=distribute.pc_relevant.none-task-blog-2defaultBlogCommendFromMachineLearnPai2default-1.control&dist_request_id=1619622904767_39963&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2defaultBlogCommendFromMachineLearnPai2default-1.control