C 和指针---阅读笔记


       只有当数组名在表达式中使用的时候,编译器才会为它产生一个指针常量(所以不要把数组名和指针等同对待)。注意,是指针常量,而不是指针变量!你不能修改指针常量的值。

      只有在两种场合下,数组名并不用指针常量来表示------就是当数组名作为sizeof操作符或单目操作符&到操作数时。sizeof 返回整个数组的长度,而不是指向数组名的指针的长度。

       int array[10];

       int *ap= array + 2; 

       在进行指针加法时会对2进行调整,调整方法:2*int  也就是将2的单位设置为array 的类型。

       注意:C到下标引用和间接访问表达式是一样的!So ,ap[0]  等价的表达式是 *(ap+(0))把0和括号去掉,就为*ap,这个就好理解了,它的值为:array[2].

    &ap 的值是无法预知到,因为你不知道编译器会把它放在什么地方;ap[-1]的值,ap现在指向array的第三个元素,所以使用偏移量-1,就可得到它到值array[1].

   2[array]也是合法的,它的值是*(array+2).



效率:

   讲效率之前,先说下linux下的反汇编:

objdump -j .text -Sl objtest | more
-S 尽可能反汇编出源代码,尤其当编译的时候指定了-g这种调试参数时,
   效果比较明显。隐含了-d参数。
-l 用文件名和行号标注相应的目标代码,仅仅和-d、-D或者-r一起使用
  使用-ld和使用-d的区别不是很大,在源码级调试的时候有用,要求
  编译时使用了-g之类的调试编译选项。
-j name 仅仅显示指定section的信息

同时发现objdump这个指令功能强大,下面是几个我认为常用的option:
objdump  -x  obj  以某种分类信息的形式把目标文档的数据组织(被分为几大块)输出   
objdump  -t  obj  输出目标文档的符号表
objdump  -h  obj  输出目标文档的section概括

       下标绝对不会比指针更有效率,但指针有时会比下标更有效率。看以下代码及其反汇编(Centos系统)

#define SIZE    50
int x[SIZE];
int y[SIZE];
int i;
int *p1,*p2;

try1()函数使用下标

void try1()                           
{                                     
 80483ee:       55                                     push   %ebp
 80483ef:       89 e5                                mov    %esp,%ebp        //以上为函数调用的初始化,保存寄存器
/home/centoslive/Documents/c_test.c:30                  
        for(i=0;i<SIZE;i++)                             
 80483f1:       c7 05 88 97 04 08 00    movl   $0x0,0x8049788   //0x8049788 为变量i的地址,初始化为0
 80483f8:       00 00 00                                     
 80483fb:       eb 26                                jmp    8048423 <try1+0x35>   //跳转
/home/centoslive/Documents/c_test.c:31                            
           x[i]=y[i];                                             //     以下10行为此函数的主循环                                        
 80483fd:       a1 88 97 04 08               mov    0x8049788,%eax    //将下标i存入寄存器
 8048402:       8b 15 88 97 04 08        mov    0x8049788,%edx     
 8048408:       8b 14 95 a0 97 04 08    mov    0x80497a0(,%edx,4),%edx  //0x80497a0为y数组的地址,相对偏移4*edx后,取内容存入edx
 804840f:       89 14 85 c0 96 04 08    mov    %edx,0x80496c0(,%eax,4)   //0x80496c0为x数组的地址,将edx存入偏移量为4*eax的地址中

/home/centoslive/Documents/c_test.c:30                                
        printf("%d\n",2[array]);                                      
        return 0;                                                     
}                                                                     
void try1()                                                           
{                                                                     
        for(i=0;i<SIZE;i++)                                           
 8048416:       a1 88 97 04 08          mov    0x8049788,%eax         
 804841b:       83 c0 01                     add    $0x1,%eax              
 804841e:       a3 88 97 04 08          mov    %eax,0x8049788         
 8048423:       a1 88 97 04 08          mov    0x8049788,%eax     //检测i是否大于50   
 8048428:       83 f8 31                      cmp    $0x31,%eax             
 804842b:       7e d0                          jle    80483fd <try1+0xf>   //小于等于则跳转 

/home/centoslive/Documents/c_test.c:32                                
           x[i]=y[i];                                                 
}                                            


try2()函数使用指针,但效果并不是很好!

void try2()
{          
 804842f:       55                                      push   %ebp
 8048430:       89 e5                               mov    %esp,%ebp
/home/centoslive/Documents/c_test.c:35                  
        for(p1=x,p2=y;p1-x<SIZE;*p1++=*p2++);           
 8048432:       c7 05 c8 98 04 08 20    movl   $0x8049720,0x80498c8   //0x8049720 x数组地址,0x80498c8  P1地址(p1指向x数组)
 8048439:       97 04 08                                           
 804843c:       c7 05 cc 98 04 08 00    movl   $0x8049800,0x80498cc  //0x8049800  y地址  0x80498cc   p2地址
 8048443:       98 04 08                                           
 8048446:       eb 20                                jmp    8048468 <try2+0x39>      //使用指针后,主循环变成了16行!!
 8048448:       8b 15 c8 98 04 08        mov    0x80498c8,%edx     //p2 指向的内容放到p1中  
 804844e:       a1 cc 98 04 08              mov    0x80498cc,%eax      
 8048453:       8b 08                              mov    (%eax),%ecx         
 8048455:       89 0a                              mov    %ecx,(%edx)         
 8048457:       83 c2 04                         add    $0x4,%edx          //调整指针
 804845a:       89 15 c8 98 04 08       mov    %edx,0x80498c8      
 8048460:       83 c0 04                       add    $0x4,%eax           
 8048463:       a3 cc 98 04 08           mov    %eax,0x80498cc      
 8048468:       a1 c8 98 04 08           mov    0x80498c8,%eax      //p1-x<SIZE ?
 804846d:       89 c2                            mov    %eax,%edx           
 804846f:       b8 20 97 04 08           mov    $0x8049720,%eax     
 8048474:       89 d1                           mov    %edx,%ecx           
 8048476:       29 c1                            sub    %eax,%ecx           
 8048478:       89 c8                           mov    %ecx,%eax           
 804847a:       3d c7 00 00 00          cmp    $0xc7,%eax          
 804847f:       7e c7                           jle    8048448 <try2+0x19>  //不大于则跳转

/home/centoslive/Documents/c_test.c:36                             
}                               
由以上代码可知,指针的使用并没有提高效率


try3()重新使用了计数器

void try3()                                  
{                                            
 80483e9:       55                      push   %ebp
 80483ea:       89 e5                   mov    %esp,%ebp
/home/centoslive/Documents/c_test.c:41                  
        for(i=0,p1=x,p2=y;i<SIZE;i++)                   
 80483ec:       c7 05 a8 97 04 08 00    movl   $0x0,0x80497a8   //   i 赋初值
 80483f3:       00 00 00                                     
 80483f6:       c7 05 88 98 04 08 e0    movl   $0x80496e0,0x8049888   //  p1=x,p2=y
 80483fd:       96 04 08                                           
 8048400:       c7 05 8c 98 04 08 c0    movl   $0x80497c0,0x804988c
 8048407:       97 04 08                                           
 804840a:       eb 2d                   jmp    8048439 <try3+0x50>
/home/centoslive/Documents/c_test.c:42                             
           *p1++=*p2++;                                            
 804840c:       8b 15 88 98 04 08       mov    0x8049888,%edx   //    *p1++=*p2++;

 8048412:       a1 8c 98 04 08          mov    0x804988c,%eax      
 8048417:       8b 08                   mov    (%eax),%ecx         
 8048419:       89 0a                   mov    %ecx,(%edx)         
 804841b:       83 c2 04                add    $0x4,%edx          //调整指针
 804841e:       89 15 88 98 04 08       mov    %edx,0x8049888      
 8048424:       83 c0 04                add    $0x4,%eax           
 8048427:       a3 8c 98 04 08          mov    %eax,0x804988c      

/home/centoslive/Documents/c_test.c:41                             
        for(p1=x,p2=y;p1-x<SIZE;*p1++=*p2++);                      
}                                                                  
                                                             
void try3()                                                        
{                                                                  
        for(i=0,p1=x,p2=y;i<SIZE;i++)                              
 804842c:       a1 a8 97 04 08          mov    0x80497a8,%eax      
 8048431:       83 c0 01                add    $0x1,%eax      // i ++    
 8048434:       a3 a8 97 04 08          mov    %eax,0x80497a8      
 8048439:       a1 a8 97 04 08          mov    0x80497a8,%eax   //  i <50?   
 804843e:       83 f8 31                cmp    $0x31,%eax          
 8048441:       7e c9                   jle    804840c <try3+0x23>

/home/centoslive/Documents/c_test.c:43                             
           *p1++=*p2++;                                            
                              


try4()使用寄存器指针变量

void try4()                           
{                                     
 80483e9:       55                      push   %ebp           //保护需要使用的寄存器
 80483ea:       89 e5                mov    %esp,%ebp
 80483ec:       57                      push   %edi     
 80483ed:       56                      push   %esi     
 80483ee:       53                      push   %ebx     
/home/centoslive/Documents/c_test.c:50                  
        register int *pt1,*pt2;                         
        register int i;                                 
        for(i=0,pt1=x,pt2=y;i<SIZE;i++)                 
 80483ef:       bf 00 00 00 00          mov    $0x0,%edi   // edi 寄存器用来存放变量  i 的值
 80483f4:       be c0 96 04 08          mov    $0x80496c0,%esi   // esi寄存器用来存放 指针变量pt1
 80483f9:       bb a0 97 04 08          mov    $0x80497a0,%ebx  // ebx 寄存器用来存放指针变量pt2
 80483fe:       eb 0d                   jmp    804840d <try4+0x24>
/home/centoslive/Documents/c_test.c:51                            
           *pt1++=*pt2++;                                         
 8048400:       8b 03                   mov    (%ebx),%eax        
 8048402:       89 06                   mov    %eax,(%esi)        
 8048404:       83 c6 04                add    $0x4,%esi          
 8048407:       83 c3 04                add    $0x4,%ebx          
/home/centoslive/Documents/c_test.c:50                            
*/                                                                
void try4()                                                       
{                                                                 
        register int *pt1,*pt2;                                   
        register int i;                                           
        for(i=0,pt1=x,pt2=y;i<SIZE;i++)                           
 804840a:       83 c7 01                add    $0x1,%edi          
 804840d:       83 ff 31                cmp    $0x31,%edi         
 8048410:       7e ee                   jle    8048400 <try4+0x17>

/home/centoslive/Documents/c_test.c:52                            
           *pt1++=*pt2++;                                         
}                                                                 


try5() 在使用寄存器指针变量到基础上消除了计数器

void try5()                            
{                                      
 80483e9:       55                      push   %ebp
 80483ea:       89 e5                 mov    %esp,%ebp
 80483ec:       56                      push   %esi     
 80483ed:       53                      push   %ebx     
/home/centoslive/Documents/c_test.c:56                  
        register int *pt1,*pt2;                         
        for(pt1=x,pt2=y;pt1<&x[SIZE];)                  
 80483ee:       bb c0 96 04 08          mov    $0x80496c0,%ebx
 80483f3:       be a0 97 04 08          mov    $0x80497a0,%esi
 80483f8:       eb 0a                   jmp    8048404 <try5+0x1b>
/home/centoslive/Documents/c_test.c:57                            
           *pt1++=*pt2++;                                         //此时主要代码达到最紧凑。。。7行
 80483fa:       8b 06                   mov    (%esi),%eax        
 80483fc:       89 03                   mov    %eax,(%ebx)        
 80483fe:       83 c3 04                add    $0x4,%ebx          
 8048401:       83 c6 04                add    $0x4,%esi        
 
/home/centoslive/Documents/c_test.c:56                            
}                                                                 
*/                                                                
void try5()                                                       
{                                                                 
        register int *pt1,*pt2;                                   
        for(pt1=x,pt2=y;pt1<&x[SIZE];)
                            
 8048404:       b8 88 97 04 08          mov    $0x8049788,%eax    
 8048409:       39 c3                   cmp    %eax,%ebx          
 804840b:       72 ed                   jb     80483fa <try5+0x11>

/home/centoslive/Documents/c_test.c:58                            
           *pt1++=*pt2++;                                         
}  
                                      


通过以上的实验可知:

1、当你根据某个固定数目的增量在一个数组中移动的时候,使用指针变量将比使用下标产生效率更高的代码。当这个增量是1并且机器具有地址自动增量模型时,这表现的更为突出。

2、声明为寄存器变量的指针通常比位于静态内存和堆栈中的指针效率更高(提高幅度取决于你使用的机器)

3、如果你可以通过测试一些已经初始化并且经过调整的内容来判断循环是否应该终止,那么你就不需要使用一个单独到计数器

4、那些必须在运行时求值的表达式较之诸如&array[SIZE],或者array+SIZE 这样到变量表达式往往代价更高!


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值