指针变量和它所指向的内存空间是两个不同的概念
由于Const在C和C++中存在差异,本篇将会对Const
在两种语言的表现异同点上进行对比探讨。
实现方式不同
在C语言中,Const
修饰的变量只是告诉编译器该变量是一个只读的变量,不能通过该变量改写器内存空间中的值,但是其本质上还是一个变量,既然是变量,就会有内存地址,因此可以通过指针间接修改该地址空间的值。
const int a = 10;
int* p = &a;
*p = 20;
printf("a = %d, *p = %d\n", a, *p);
-------------结果------------------
a = 20, *p = 20
在C++中Const
修饰的变量被称为常量,其值存放在常量表中,在使用常量时,编译器回到常量表中查询对应的常量,并将其替换,这部分没有涉及内存分配,因此对其取地址是没有意义的。但是当我们非要对该常量去地址时,则编译器会为其临时分配一个内存,并将常量值存入该临时内存中,事实上,在C++中规定必须用const修饰的指针来指向const修饰的常量。虽然可以使用强制转换的方式,对Const
修饰的常量进行去地址,并将其赋值给一个非Const
修饰的指针(最好不要这样做),但打这个指针上的任何改动都只会影响到临时分配的内存空间,而不会影响到原常量上。
const int a = 10;
int* p = (int *)&a;
*p = 20;
printf("a = %d, *p = %d\n", a, *p);
-------------结果------------------
a = 10, *p = 20
变量的文件作用域
在C语言中,访问一个变量之前,该变量必须要被预先定义,当访问一个由外部文件定义的变量时,则必须要提前声明该变量。来看下面几个例子。
// main.c
extern int a;
int main() {
printf("a = %d\n", a);
return 0;
}
//ln_const.c
int a = 128;
--------结果-------
a = 128
上面的例子是一个标准C语言访问外部变量的例子。我们编写代码时也应该遵守这样的规则。但是,总有写人不是那么规范,例如可以在main.c
文件中将extern
关键字去掉。
// main.c
int a;
int main() {
printf("a = %d\n", a);
return 0;
}
//ln_const.c
int a = 128;
--------结果-------
a = 128
我们发现实际上结果并没有变化,因为编译器在编译时,如果在当前文件中该变量没有被定义,则会从其他文件中寻找定义并链接。因此结果是没有问题的。那么如果变量a的定义被设定成文件内私有时,将会发生什么呢?
// main.c
int a;
int main() {
printf("a = %d\n", a);
return 0;
}
// ln_const.c
static int a = 128;
--------结果-------
a = 0
发生这种现象的原因是,编译器没有找到该变量的外部定义,则直接将声明默认为定义,因此变量a是一个默认赋值。事实上extern
关键字的作用就是,告诉编译器,该变量的值是由外部文件定义的。因此当我们声明一个外部变量时,如果编译器无法再外部找到该变量的定义,则会无法编译通过。
// main.c
extern int a;
int main() {
printf("a = %d\n", a);
return 0;
}
// ln_const.c
static int a = 128;
--------结果-------
编译失败,无法解析外部符号a
那么如果我们在外部定义了一个Const
变量,情况是否会有不同呢?在标准情况下,声明和定义,应该是保持一致的。因此标准做法应该是这样的。
// main.c
extern const int a ;
int main() {
printf("a = %d\n", a);
return 0;
}
// ln_const.c
const int a = 128;
-----结果---------
a = 128
C语言的难点之一就是规范标准,总有人会在声明时忘记const
关键字,但是结果也是正确的。
// main.c
extern int a ;
int main() {
printf("a = %d\n", a);
return 0;
}
// ln_const.c
const int a = 128;
-----结果---------
a = 128
既然a在声明时并没有Const
修饰是不是意味着,可以直接修改a呢?
// main.c
extern int a ;
int main() {
a = 20;
printf("a = %d\n", a);
return 0;
}
// ln_const.c
const int a = 128;
-----结果---------
编译失败,运行时异常
这里,我们可以看出,变量的声明帮助编译器进行语法检查,但变量的定义决定了运行时的行为。
当static
关键字和Const
关键字同时修饰变量时,Const
是否会修改变量的文件作用域呢?
// main.c
extern int a ;
int main() {
printf("a = %d\n", a);
return 0;
}
// ln_const.c
static const int a = 128;
-----结果---------
编译失败,无法解析外部符号a
总结:在C语言中,变量文件作用域一般都是外部链接,除非使用static关键字修饰,Const关键字并不会改变变量的文件作用域