我们都知道,在c语言中我们使用const表示当前的变量是只读的,但是这个只读是否是绝对的,其实并不是,如果我们使用特殊的手段,我们其实是可以改变的,请看下面的代码
#include <stdio.h>
int main(void)
{
const int i = 0;
int j = 1;
int *p = &j;
p[1] = 1;
printf("%d\n", i);
return 0;
}
将其定义为.c为后缀的,使用vc++6.0编译运行结果为1,这是为什么?我不是定义i为const吗,而且我在程序中并没有改变i的值啊?
讨论这个之前,我们来看一下这个程序编译的汇编代码
3: int main(void)
4: {
00401010 push ebp
00401011 mov ebp,esp
00401013 sub esp,4Ch
00401016 push ebx
00401017 push esi
00401018 push edi
00401019 lea edi,[ebp-4Ch]
0040101C mov ecx,13h
00401021 mov eax,0CCCCCCCCh
00401026 rep stos dword ptr [edi]
5: const int i = 0;
00401028 mov dword ptr [ebp-4],0
6: int j = 1;
0040102F mov dword ptr [ebp-8],1
7: int *p = &j;
00401036 lea eax,[ebp-8]
00401039 mov dword ptr [ebp-0Ch],eax
8:
9: p[1] = 1;
0040103C mov ecx,dword ptr [ebp-0Ch]
0040103F mov dword ptr [ecx+4],1
10:
11: printf("%d\n", i);
00401046 mov edx,dword ptr [ebp-4]
00401049 push edx
0040104A push offset string "%d\n" (0042201c)
0040104F call printf (00401080)
00401054 add esp,8
12:
13: return 0;
00401057 xor eax,eax
14: }
其中最重要的一句
00401019 lea edi,[ebp-4Ch]
这句是为当前的函数分配栈,什么意思就是将栈顶往上移,使得栈空间变大,从而分配空间,这也是为什么c语言函数调用的消耗其实很小的原因,
我们看下面两句:
5: const int i = 0;
00401028 mov dword ptr [ebp-4],0
<pre name="code" class="plain">6: int j = 1;
0040102F mov dword ptr [ebp-8],1
这就是我们定义的两个变量,一个是const类型的,我们可以看到在声明变量的时候c语言的处理方式其实是压栈,而且在生成的汇编代码中其实已经没有了变量名的信息,而是变成的地址,
而且我们可以看到局部变量是按顺序压入函数栈中的,这也就是我们如果使用后面定义的变量的指针往下移就会移到上面定义的变量中去的原因,这时我们就可以利用这个指针修改这个const变量了,
但是如果我们将文件名称定义为.cpp类型结果去不是这样,这时为什么呢?我将最重要影响这个结果的汇编代码放在下面
10: printf("%d\n", i);
00401046 push 0
00401048 push offset string "%d\n" (0042201c)
0040104D call printf (00401080)
00401052 add esp,8
大家可以看到,此时i并没有使用变量,而是在编译生成汇编代码的时候已经使用了0,这也就是c++将const变量称之为常量的原因了,上面的代码在vc++6.0中可以运行出相应的结果,但是在vs2013上运行并不能得到相同的结果,我通过查看内存内容发现,i和j相隔了12个自己,我不知道这时什么原因!!为什么在vs2013使用了这种实现