深入理解char [] 和 char * ,const char[]和 const char*--反汇编分析

首先这个是我在2012-06-15日去某公司面试遇到的问题,当时写错了,被鄙视了,现在痛定思痛,深入分析一下。
 
 1     char a[]="abc";
 2     char b[]="abc";
 3 
 4     char *c="abc";
 5     char *d="abc";
 6 
 7     const char e[]="abc";
 8     const char f[]="abc";
 9 
10     const char *g="abc";
11     const char *h="abc";
12      printf("%i\n",a==b);  
13      printf("%i\n",c==d);
14      printf("%i\n",e==f);
15      printf("%i\n",g==h);
 
正确答案是:0   1   0   1
额,悲催的是我刚好答反了,不知道当时怎么想的了。
现在我把这段程序用objdump反汇编后来分析分析:
 
 1  8048594:    55                       push   %ebp
 2  8048595:    89 e5                    mov    %esp,%ebp
 3  8048597:    83 ec 20                 sub    $0x20,%esp
 4  804859a:    a1 00 87 04 08           mov    0x8048700,%eax
 5  804859f:    89 45 fc                 mov    %eax,-0x4(%ebp)
 6  80485a2:    a1 00 87 04 08           mov    0x8048700,%eax
 7  80485a7:    89 45 f8                 mov    %eax,-0x8(%ebp)
 8  80485aa:    c7 45 f4 00 87 04 08     movl   $0x8048700,-0xc(%ebp)
 9  80485b1:    c7 45 f0 00 87 04 08     movl   $0x8048700,-0x10(%ebp)
10  80485b8:    a1 00 87 04 08           mov    0x8048700,%eax
11  80485bd:    89 45 ec                 mov    %eax,-0x14(%ebp)
12  80485c0:    a1 00 87 04 08           mov    0x8048700,%eax
13  80485c5:    89 45 e8                 mov    %eax,-0x18(%ebp)
14  80485c8:    c7 45 e4 00 87 04 08     movl   $0x8048700,-0x1c(%ebp)
15  80485cf:    c7 45 e0 00 87 04 08     movl   $0x8048700,-0x20(%ebp)
16  80485d6:    b8 00 00 00 00           mov    $0x0,%eax
17  80485db:    c9                       leave  
18  80485dc:    c3                       ret
 
我们来把c语言代码和汇编代码对比着分析:
前三句是进入main函数时保护现场,压栈操作,不用管。
char a[]="abc"; 
对应:
mov    0x8048700,%eax
mov    %eax,-0x4(%ebp)
对比着这两句汇编代码来分析这句c语言代码:
  1. 因为“abc”是常量,首先在常量区申请一块内存存放“abc”,地址为:0x8048700;
  2. 然后把0x8048700地址指向的数据拷贝到寄存器%eax中;
  3. 最后把%eax的值拷贝到-0x4(%ebp)中,也就是字符数组a中。

我们知道%ebp是一个栈寄存器,所以从这里看出字符数组的数据是存放在栈上的。

char b[] ="abc";对应6,7行汇编代码,和上面一样。

char *c="abc";

对应:

movl   $0x8048700,-0xc(%ebp)

我们看到汇编代码中是把$0x8048700这个立即数直接拷贝到-0xc(%ebp)中的。

$0x8048700是什么呢?是字符串“abc”的地址,编译器很聪明,同样的字符串在内存里只存放了一份。

地址前面加上$是说明这个操作是个立即数寻址方式,也就是把这个数字拷贝到-0xc(%ebp)。

从这我们可以看出字符指针本身是在栈上,它指向的值在常量区的。

  继续看汇编代码,我们发现const 型和非const型的汇编代码是一样的。这是因为const的实现机制是编译器在编译时会对const型变量进行检查,如果发现违反const型用法则报错。就是说const型变量在编译期间是不允许改变的,那么在运行时呢?可以的,只要骗过了编译器就可以改变,具体可以看《高质量程序设计指南--c++/c语言》86页的程序。

现在我们来回答下这个问题:
printf("%i\n",a==b);
数组的名称是指向这个数组的第一个单元的指针,因此a,b的值是数组a,b的首地址。
这两个数组的地址当然是不一样的,因此是0.
printf("%i\n",c==d);
字符指针c和d的值是指向"abc"这个常量的地址,因此是一样的。答案是1.
const型字符数组和const字符指针同理。
 
reference:
《高质量程序设计指南--c++/c语言》 第五章 c++/c常量
《深入理解计算机系统》 第三章 程序的机器级表示
    
 作者:辛未
 转载请署名!
 2012-06-17  13:31:58
 
 
 
 
 
 

转载于:https://www.cnblogs.com/sheyong/archive/2012/06/17/2012-06-17_char_array_and_char_pointer.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值