∇ \nabla ∇ 联系方式:
e-mail: FesianXu@gmail.com
QQ: 973926198
github: https://github.com/FesianXu
知乎专栏: 计算机视觉/计算机图形理论与应用
微信公众号:
const
和volatile
修饰符统称为cv修饰符
,用于指示编译器是否允许一个程序中的某个变量的内存是否在初始化后,仍允许被修改。其中的volatile
我们已经在前文[1]中讨论过了,我们讨论下const
的一些特性。我们知道,cv修饰符
都是给编译器看的,用于指导编译过程中的优化(如volatile
)或者用户非法变量修改行为(如const
),因此这俩个修饰符只能保证编译时的操作合乎设计时候的需求,但是如果涉及到运行时(running time)的一些操作,是无法保证的。我们本文讨论const
修饰后的变量,被运行时『修改』的例子。
如果我们正常使用const
,理应如下所示:
const int var = 10;
int var_b = 100;
var = 100; // 非法操作,因为var是const类型,初始化后不能被修改。
var_b = 10; // 合法操作,正常的赋值
然而,我们不能确保运行时,被const
修饰的变量内存,被其他程序,或者自行设计错误,或者黑客行为修改,举个例:
#include <stdio.h>
int main(void) {
int a = 10;
const int b = 9;
int c = 8;
printf("%d\t%d\t%d\n\r", a, b, c);
int* pa = &a;
const int* pb = &b;
int* pc = &c;
printf("%x\t%x\t%x\n\r", pa,pb,pc);
*(pa+1) = 100; // modify the first time
printf("%d\n\r", *(pa+1));
*(pc-1) = 300;
printf("%x\t%x\t\n\r", (pa+1), (pc-1));
printf("%d\n\r", (pa+1) == (pc-1));
printf("%d\n\r", (pa+1) == pb);
printf("%d\t%d\t%d\t%d\n\r",a,*(pa+1),c,*(pb));
return 0;
}
用g++ test_const.cpp
编译,用./a.out
输出结果,代码输出为:
我们可以发现,通过栈[2]上相邻的变量的地址做偏移,可以实现间接地对const
修饰的变量进行修改,这种行为会意料之外的修改常量,非常的危险,我们的代码中需要检查涉及到指针偏移的操作,检查是否会出现越界的情况。
注意到,如果代码中的输出从:
printf("%d\t%d\t%d\t%d\n\r",a,*(pa+1),c,*(pb));
改成
printf("%d\t%d\t%d\t%d\n\r",a,*(pa+1),c,b);
结果是不一样的,后者的结果仍然是输出b = 9
,那是因为C++在编译时对常量进行折叠,因此直接输出3这个立即数了,而不是从内存里面取出常量再输出,这一点要注意。
PS: 注意,有些编译器中,依次定义的变量a,b,c
的地址是降序的,而在有些编译器中是升序的,可以用以下代码检测下。如果是降序的,那么以上测试例子里面需要对地址操作进行取反,把+
变为-
,把-
变为+
。
int a = 10;
const int b = 9;
int c = 8;
printf("%d\t%d\t%d\n\r", a, b, c);
int* pa = &a;
const int* pb = &b;
int* pc = &c;
printf("%x\t%x\t%x\n\r", pa,pb,pc);
评论区有个朋友提到:
FX,const int b = 9;这个b是放在常量区,不可被修改。const int* pb = &b;这个中pb的指向是可以修改的,你间接修改的是pb的指向,不是常量b,我觉得是这样的
其实这个和编译器有关,如果你用g++
,那么以下代码的输出是不一致的,b
还是原值,*(pb)
是修改后的值,这是因为c++会对const
进行常量折叠,导致尝试修改const变量的地址这个行为失效;然而如果你采用gcc
进行编译,那么以下输出是一致的,因为C语言的const并不会进行常量折叠。
printf("%d\t%d\t%d\t%d\n\r",a,*(pa+1),c,*(pb));
printf("%d\t%d\t%d\t%d\n\r",a,*(pa+1),c,b);
Reference
[1]. https://blog.csdn.net/LoseInVain/article/details/103356324
[2]. https://blog.csdn.net/LoseInVain/article/details/103183829