R.Ihskaka
新手上路
因为学校的机器没有linux,所以我用了xp+vc6,文件名为test.c
代码是在Release模式下debug的,因为DEBUG模式会对环境有依赖.
这个是源码:
#include<stdio.h>
#define SUCCESS 1
#define FAILURE 0
void main()
{
char *lpTest = "ABCD";
printf("The String is: %s n ",lpTest);
*(lpTest+1) = 'X';
printf("The String is: %s n ",lpTest);
}
发表于: 2005-01-15 11:35
在下新人,也想参与下讨论,哪里说的不对,请各位包涵并指出
因为学校的机器没有linux,所以我用了xp+vc6,文件名为test.c
代码是在Release模式下debug的,因为DEBUG模式会对环境有依赖.
这个是源码:
#include<stdio.h>
#define SUCCESS 1
#define FAILURE 0
void main()
{
char *lpTest = "ABCD";
printf("The String is: %s n ",lpTest);
*(lpTest+1) = 'X';
printf("The String is: %s n ",lpTest);
}
这是由vC6的Debug的汇编代码,其中带///////// 的为c代码,下面的是对应的汇编代码:
///void main() //这行自己加的,就从这里开始了
{
00401000 55 push ebp
00401001 8B EC mov ebp,esp
00401003 51 push ecx
6: char *lpTest = "ABCD"; ////////////////
00401004 C7 45 FC 30 70 40 00 mov dword ptr [lpTest],offset ___xt_z+8 (00407030)
7: printf("The String is: %s n ",lpTest);////////////////
0040100B 8B 45 FC mov eax,dword ptr [lpTest]
0040100E 50 push eax
0040100F 68 38 70 40 00 push offset ___xt_z+10h (00407038)
00401014 E8 1F 00 00 00 call _printf (00401038)
00401019 83 C4 08 add esp,8
8: *(lpTest+1) = 'X';////////////////
0040101C 8B 4D FC mov ecx,dword ptr [lpTest]
0040101F C6 41 01 58 mov byte ptr [ecx+1],58h
9: printf("The String is: %s n ",lpTest);////////////////
00401023 8B 55 FC mov edx,dword ptr [lpTest]
00401026 52 push edx
00401027 68 50 70 40 00 push offset ___xt_z+28h (00407050)
0040102C E8 07 00 00 00 call _printf (00401038)
00401031 83 C4 08 add esp,8
10: }
00401034 8B E5 mov esp,ebp
00401036 5D pop ebp
00401037 C3 ret
程序运行时,其实lpTest很明显是存放在堆栈里的(0x012ff7c) 从汇编上看到,lpTest开始时,push ecx,并将lpTest指向ecx寄存器的内容为地址的区域,在
mov dword ptr [lpTest],offset ___xt_z+8 (00407030)
后,lpTest才真正指向了定义的"ABCD".而这个"ABCD"的存放地址是0x00407030 . 可见赋值号右边的常量其实是开辟在一个单独的区域里,而且似乎所有的字符常量都是这样.在printf()里的"The String is: %s"也是存放在0x00407030之后的地址上,调用时push的.
这样,对于lpTest本身来说,它其实就是变量而已,可以改变它指向的内容是很正常的.(不正常C语言早浮云了^_^ ) 而对于赋值号右边的字符串常量,它们是单独存放在一个区域的,指针依靠地址来使用他们.
其实只要将 char *lpTest = "ABCD" 改为: const char *lpTest = "ABCD"
就不可以再改变它的数值了.而加上const后的汇编代码,和没有加上时其实是一样的,"ABCD"仍然放在0x00407030. 只是如果你加了const,还试图改变lpTest的数值,那么编译时就会失败,这个看起来是由编译器保证的.这个我不能肯定,编译原理还没学,说不清楚 (>_<)
那么如果是: const char Arry[]="WXYZ" 呢?
00401000 55 push ebp
00401001 8B EC mov ebp,esp
00401003 83 EC 0C sub esp,0Ch
8: const char Arry[]="WXYZ"; ////////////////
00401006 A1 30 70 40 00 mov eax,[___xt_z+8 (00407030)]
0040100B 89 45 F8 mov dword ptr [Arry],eax
0040100E 8A 0D 34 70 40 00 mov cl,byte ptr [___xt_z+0Ch (00407034)]
00401014 88 4D FC mov byte ptr [ebp-4],cl
.........................
其实还是一样,字符串常量都是开辟在0x00407030的,但是用了const,就会把这个地址的内容,拷贝到堆栈中去,然后利用
mov cl,byte ptr [___xt_z+0Ch (00407034)]
mov byte ptr [ebp-4],cl
来调整一下,使Arry的地址精确指向堆栈中的4个字节,这样就是数组字符串常量了