关于char * c="hello"与char c[]="hello"的区别

       前两天在VC群里,看一初学者在群里问char * c="hello"与char c[]="hello"的区别。估计有很多人说不清楚。
      我现在来分析下他们直接真的区别。现在我打开VC写一短很小的代码,然后我们来反汇编。看真的区别。

#include <stdio.h>
void main()
{
    
char * c = "hello";
    printf(
"%s\n",c);
}

反汇编结果如下

00401010   push        ebp
00401011   mov         ebp,esp
00401013   sub         esp,44h
00401016   push        ebx
00401017   push        esi
00401018   push        edi
00401019   lea         edi,[ebp-44h]
0040101C   mov         ecx,11h
00401021   mov         eax,0CCCCCCCCh  ;这里之前是VC debug特有的,主要是为了调试创建44h个自己内存,全部初始化CC 也就是int3 调试器用的。
00401026   rep stos    dword ptr [edi]
4:        char * c = "hello";
00401028   mov         dword ptr [ebp-4],offset string "hello" (00422020;把字符串的地址放进了第一个局部变量,c是变量分配在堆栈中也就是doord prt[bp-4]
5:        printf("%s\n",c);
0040102F   mov         eax,dword ptr [ebp-4]
00401032   push        eax
00401033   push        offset string "%s\n" (0042201c)
00401038   call        printf (00401070)
0040103D   add         esp,8

总结下:char * c = "hello"; c是个分配在堆栈中的一个变量。里面装的是字符串hello的首地址,而hello是常量区。PE文件在编译的时候就确定了的。

下面再来看char c[]="hello";

#include <stdio.h>
void main()
{
    
char c[] = "hello";
    printf(
"%s\n",c);
}

反汇编:

00401019   lea         edi,[ebp-48h]
0040101C   mov         ecx,12h
00401021   mov         eax,0CCCCCCCCh
00401026   rep stos    dword ptr [edi];前面是调试用的不管
4:        char c[] = "hello";
00401028   mov         eax,[string "hello" (00422020)]
0040102D   mov         dword ptr [ebp-8],eax;把hello的前4个字符放入[ebp-8]的堆栈内存中
00401030   mov         cx,word ptr [string "hello"+4 (00422024)]
00401037   mov         word ptr [ebp-4],cx;把hello的第5个字符放入[ebp-4]高地址中
5:        printf("%s\n",c);
0040103B   lea         edx,[ebp-8]
0040103E   push        edx
0040103F   push        offset string "%c\n" (0042201c)
00401044   call        printf (00401070)
00401049   add         esp,8

上面我只是用"hello"做例子,如果是helloworld放入char c[]呢,那会是这样的。
dword ptr[ebp-c]="hell"  dword ptr[ebp-8]="owor" word ptr[ebp-4]="ld"这样放。
总结下:
也就是说char []c = "hello";
"hello"是放在堆栈中保存的,跟上面的那个例子不同,由于hello是堆栈中的所以是可以修改的。而常量区里的是不可以修改的。因为PE的内存页属性是只读的。当然可以有办法强行修改它。那属于HACK技术了。
那c保存在哪里呢?c根本在内存中不存在,只是编译器的一个标记,用于编译期来计算地址用的。用完就不要了。   
                                                                                                                                                                          转载请标明出处,谢谢.

posted @ 2008-05-06 16:45  debugzhu  阅读(906)  评论(3编辑  收藏  举报