关与对《C语言深度解剖》函数指针的进一步探讨

在《C语言深度解剖》中的4.7.2一节——函数指针的使用中有一个例子~~~

有代码,有真相~~~

#include <stdio.h>
#include <string.h>

char * fun(char  *p1,char *p2)
{
    int i=0;
    i=strcmp(p1,p2);
    if(i==0)
    {
        return p1;
    }
    else
        return p2;
}

int main()
{
    char *(*pf)(char * ,char *);
    pf=fun;
    printf("%s\n", (*pf)("aa","bb"));

    return 0;
}
输出结果:bb

然后书中说道“在pf=fun;这条语句里面,fun和&fun是一样的,因为函数名被编译之后本身就是一个地址(VC6)”。

也就是说如果fun可以看成一个变量,我是说如果,那么就是“&fun”这个内存地址中存放这自己的地址值~~~
以下是我在gcc下编译通过并显示的结果:

#include <stdio.h>
#include <string.h>

char * fun(char  *p1,char *p2)
{
    int i=0;
    i=strcmp(p1,p2);
    if(i==0)
    {
        return p1;
    }
    else
    {
        return p2;
    }
}

int main()
{
    char *(*pf)(char * ,char *);
    pf=fun;
    printf("%s\n", (*pf)("aa","bb"));
    printf("pf:%x ,&pf: %x ,*pf:%x fun:%x &fun:%x *fun:%x \n", pf,&pf,*pf,fun,&fun,*fun);

    return 0;
}
结果:

bb
pf:400584 ,&pf: e4b8edb8 ,*pf:400584 fun:400584 &fun:400584 *fun:400584 


它(gcc)竟然让*fun通过编译并运行了,它到底做了什么,可以让一个函数变成变量~~~

当然以上结果显示我之前的分析是一致的,但是真相真的是这样么~~~

可能没那么简单~~~

因为我在vs2008里面不是这么个情况的~~~

上vs下面的代码主函数的反汇编代码:

int main()
{
004135A0  push        ebp 
004135A1  mov         ebp,esp
004135A3  sub         esp,0CCh
004135A9  push        ebx 
004135AA  push        esi 
004135AB  push        edi 
004135AC  lea         edi,[ebp-0CCh]
004135B2  mov         ecx,33h
004135B7  mov         eax,0CCCCCCCCh
004135BC  rep stos    dword ptr es:[edi]
        char *(*pf)(char *p1,char *p2);
        pf=&fun;
004135BE  mov         dword ptr [pf],offset @ILT+295(_fun) (41112Ch)
        printf("%s\n",(*pf)("aa","bb"));
004135C5  mov         esi,esp
004135C7  push        offset string "bb" (415744h)
004135CC  push        offset string "aa" (41573Ch)
004135D1  call        dword ptr [pf]
004135D4  add         esp,8
004135D7  cmp         esi,esp
004135D9  call        @ILT+320(__RTC_CheckEsp) (411145h)
004135DE  mov         esi,esp
004135E0  push        eax 
004135E1  push        offset string "%s\n" (415740h)
004135E6  call        dword ptr [__imp__printf (4182C4h)]
004135EC  add         esp,8
004135EF  cmp         esi,esp
004135F1  call        @ILT+320(__RTC_CheckEsp) (411145h)
        printf("pf:%x,&pf:%x,*pf:%x,fun:%x,&fun:%x,*fun%x,\n",pf,&pf,*pf,fun,&fun,*fun);
004135F6  mov         esi,esp
004135F8  push        offset @ILT+295(_fun) (41112Ch)
004135FD  push        offset @ILT+295(_fun) (41112Ch)
00413602  push        offset @ILT+295(_fun) (41112Ch)
00413607  mov         eax,dword ptr [pf]
0041360A  push        eax 
0041360B  lea         ecx,[pf]
0041360E  push        ecx 
0041360F  mov         edx,dword ptr [pf]
00413612  push        edx 
00413613  push        offset string "pf:%x,&pf:%x,*pf:%x,fun:%x,&fun:"... (415A00h)
00413618  call        dword ptr [__imp__printf (4182C4h)]
0041361E  add         esp,1Ch
00413621  cmp         esi,esp
00413623  call        @ILT+320(__RTC_CheckEsp) (411145h)

        getchar();
00413628  mov         esi,esp
0041362A  call        dword ptr [MSVCR90D_NULL_THUNK_DATA (4182C0h)]
00413630  cmp         esi,esp
00413632  call        @ILT+320(__RTC_CheckEsp) (411145h)
        return 0;
00413637  xor         eax,eax
}
00413639  push        edx 
0041363A  mov         ecx,ebp
0041363C  push        eax 
0041363D  lea         edx,[ (413660h)]
00413643  call        @ILT+130(@_RTC_CheckStackVars@8) (411087h)
00413648  pop         eax 
00413649  pop         edx 
0041364A  pop         edi 
0041364B  pop         esi 
0041364C  pop         ebx 
0041364D  add         esp,0CCh
00413653  cmp         ebp,esp
00413655  call        @ILT+320(__RTC_CheckEsp) (411145h)
0041365A  mov         esp,ebp
0041365C  pop         ebp 
0041365D  ret             
0041365E  mov         edi,edi
00413660  db          01h 
00413661  db          00h 
00413662  db          00h 
00413663  db          00h 
00413664  db          68h 
00413665  db          36h 
00413666  db          41h 
00413667  db          00h 
00413668  db          f8h 
00413669  db          ffh 
0041366A  db          ffh 
0041366B  db          ffh 
0041366C  db          04h 
0041366D  db          00h 
0041366E  db          00h 
0041366F  db          00h 
00413670  db          74h 
00413671  db          36h 
00413672  db          41h 
00413673  db          00h 
00413674  db          70h 
00413675  db          66h 
00413676  db          00h  
ps:还没有进如到汇编的level~~~做个标记先~~~

结果如下:

说明:vs监视器和print输出的地址(vs的print和gcc下的print一样)值不一样,估计是个bug吧,print输出时对的,而且vs监视器不认为*fun是一个变量~~~但也还是能够输出~~~

那么按照vs监视器来说fun还真是个变量~~~是char*(char *,char *),也就是函数指针的类型~~~

后记:觉得有些C语言的特性不能单从C语言的语法角度来解释,因为C语言是相对比较低级的语言,和硬件(CPU及体系结构)由很大的相关性,所以如果要深入理解,还是得从更低级的汇编的角度来理解~~~好吧,给自己找个了解汇编找个动力先~~~



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值