| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 684 人关注过本帖
标题:[貌似已解决]关于函数指针的2个问题,请帮帮忙.谢谢
只看楼主 加入收藏
casio1374633
Rank: 1
等 级:新手上路
帖 子:22
专家分:0
注 册:2010-3-11
收藏
 问题点数:0 回复次数:9 
[貌似已解决]关于函数指针的2个问题,请帮帮忙.谢谢
第一个:
===============================
请帮忙看下这个函数的指针如何理解?谢谢
------------------------------------------------------
#include <stdio.h>
#include <string.h>
void        tell_me(int f(const char *, const char *));
int main(void)
{
        tell_me(strcmp);
        tell_me(main);
        return 0;
}
void        tell_me(int f(const char *, const char *))
{
        if (f == strcmp)  /* <-----我不理解这里*/
                printf("Address of strcmp(): %p\n", f);
        else
                printf("Function address: %p\n", f);
}
--------------------------------------------------------------
其中我不理解的是,这个程序表达的应该是说f是一个指向函数的指针,判断的时候是判断f是否指向函数strcmp,如果是的话,就输出strcmp这个函数的地址.如果不是,就输出main函数的地址
因为函数名可以作为指针,所以if (f == strcmp)应该是说判断2个指针的地址是否相同对吧?
我用gdb 断点到此,print f和printfstrcmp得到的是不同的地址啊,并且可以发现f和*f的内容居然一样,strcmp和*strcmp也一样,请问是什么原因,如何解释?
(gdb) print f
$1 = (int (*)(const char *, const char *)) 0x8048310 <strcmp@plt>
(gdb) print strcmp
$2 = {<text variable, no debug info>} 0xb7e59d20 <strcmp>
(gdb) n
16                        printf("Address of strcmp(): %p\n", f);
(gdb) print strcmp
$3 = {<text variable, no debug info>} 0xb7e59d20 <strcmp>
(gdb) print *strcmp
$4 = {<text variable, no debug info>} 0xb7e59d20 <strcmp>
(gdb) print *f
$5 = {int (const char *, const char *)} 0x8048310 <strcmp@plt>
(gdb) n
Address of strcmp(): 0x8048310
19        }
(gdb) n
后来我查到plt是指的过程链接表,是不是说只有在执行到f == strcmp时候,才把f的地址和strcmp的位置指向同一位置?

===========================================================
第二个:
------------------------------------------------------------------------------
字符串在函数调用过程中的输出,请帮忙看下.请帮忙看下,为什么出错?
-----------------------------------------------------------------------------------------
#include <stdio.h>
#include <string.h>
int main(void)
{
        char        p1[20] = "abc", *p2 = "pacific sea";
        printf("%s        %s         %s\n", p1, p2, strcat(p1, p2));  /*<-----问题出在这里*/
        return 0;
}
--------------------------------------------------------------------------------------------------------------
输出我的认为应该是先输出p1, p2以后再执行strcat. 但是实际输出的情况:
abcpacific sea        pacific sea         abcpacific sea
可以发现strcat先于p1执行,改变了p1的内容,请问这个内部是怎么的顺序?难道printf不是顺序执行的?

谢谢各位


[ 本帖最后由 casio1374633 于 2010-3-13 15:41 编辑 ]
搜索更多相关主题的帖子: 指针 函数 
2010-03-13 12:47
hzh512
Rank: 9Rank: 9Rank: 9
等 级:蜘蛛侠
威 望:6
帖 子:234
专家分:1333
注 册:2009-6-5
收藏
得分:0 
对第一个问题   
如下红色的哪几行,main与strcmp此时为常量(你也会发现没有.data段),在汇编代码中他是把这两个常量写入函数堆栈,然后调用函数,作出对比,然后输出。而你所说的 f ,也就是函数参数,实际上它只作为预分配的参考(汇编代码中,你是找不到 f 的)。
.file    "1.c"
    .text
.globl main
    .type    main, @function
main:
    leal    4(%esp), %ecx
    andl    $-16, %esp
    pushl    -4(%ecx)
    pushl    %ebp
    movl    %esp, %ebp
    pushl    %ecx
    subl    $4, %esp
    movl    $strcmp, (%esp)
    call    tell_me
    movl    $main, %eax
    movl    %eax, (%esp)
    call    tell_me
    movl    $0, %eax
    addl    $4, %esp
    popl    %ecx
    popl    %ebp
    leal    -4(%ecx), %esp
    ret
    .size    main, .-main
    .section    .rodata
.LC0:
    .string    "Address of strcmp(): %p\n"
.LC1:
    .string    "Function address: %p\n"
    .text
.globl tell_me
    .type    tell_me, @function
tell_me:
    pushl    %ebp
    movl    %esp, %ebp
    subl    $8, %esp
    cmpl    $strcmp, 8(%ebp)
    jne    .L4
    movl    8(%ebp), %eax
    movl    %eax, 4(%esp)
    movl    $.LC0, (%esp)
    call    printf
    jmp    .L6
.L4:
    movl    8(%ebp), %eax
    movl    %eax, 4(%esp)
    movl    $.LC1, (%esp)
    call    printf
.L6:
    leave
    ret
    .size    tell_me, .-tell_me
    .ident    "GCC: (Ubuntu 4.3.3-5ubuntu4) 4.3.3"
    .section    .note.GNU-stack,"",@progbits

编程=用几种语言在某个或几个平台上通过抽象思维运用一系列算法来解决现实中问题的手段
2010-03-13 13:44
hzh512
Rank: 9Rank: 9Rank: 9
等 级:蜘蛛侠
威 望:6
帖 子:234
专家分:1333
注 册:2009-6-5
收藏
得分:0 
关于第二个问题,strcat(char *dest,char *src) 是把src所指字符串添加到dest结尾处(覆盖dest结尾处的'\0')并添加'\0'。
而且,printf函数执行确实有顺序,平台不同,所支持的库不同,所以顺序也有可能不同。

编程=用几种语言在某个或几个平台上通过抽象思维运用一系列算法来解决现实中问题的手段
2010-03-13 14:12
玩出来的代码
Rank: 11Rank: 11Rank: 11Rank: 11
来 自:河南新乡
等 级:贵宾
威 望:11
帖 子:742
专家分:2989
注 册:2009-10-12
收藏
得分:0 
不同的编译器printf的函数参数进栈顺序不同,printf函数中的strcat可以看反汇编代码,
下面是在VC下的反汇编。
程序代码:
6:            printf("%s\t%s\t%s\n", p1, p2, strcat(p1, p2));  /*<-----问题出在这里*/
00401045   mov         edx,dword ptr [ebp-18h]
00401048   push        edx
00401049   lea         eax,[ebp-14h]
0040104C   push        eax
0040104D   call        strcat (00401130)       //可以看到是先调用strcat函数的,
00401052   add         esp,8
00401055   push        eax
00401056   mov         ecx,dword ptr [ebp-18h]
00401059   push        ecx
0040105A   lea         edx,[ebp-14h]
0040105D   push        edx
0040105E   push        offset string "%s\t%s\t%s\n" (0042201c)
00401063   call        printf (004010a0)                        //最后调用printf函数输出
00401068   add         esp,10h

离恨恰如春草,更行更远还生。
2010-03-13 15:13
玩出来的代码
Rank: 11Rank: 11Rank: 11Rank: 11
来 自:河南新乡
等 级:贵宾
威 望:11
帖 子:742
专家分:2989
注 册:2009-10-12
收藏
得分:0 
程序代码:
00401090   push        ebp                      //第一题的反汇编
00401091   mov         ebp,esp
00401093   sub         esp,40h
00401096   push        ebx
00401097   push        esi
00401098   push        edi
00401099   lea         edi,[ebp-40h]
0040109C   mov         ecx,10h
004010A1   mov         eax,0CCCCCCCCh                  //应该说在函数传递时,f与strcmp的地址都相同
004010A6   rep stos    dword ptr [edi]
13:       printf("%0x\t%0x\n",f,strcmp);             //看这里,输出f与strcmp的地址是相同的
004010A8   push        offset strcmp (004011a0)
004010AD   mov         eax,dword ptr [ebp+8]
004010B0   push        eax
004010B1   push        offset string "%0x\t%0x\n" (0042201c)
004010B6   call        printf (00401120)
004010BB   add         esp,0Ch
14:       if (f == strcmp)  /* <-----我不理解这里*/                     //比较后,输出的地址同样是一样的,
004010BE   cmp         dword ptr [ebp+8],offset strcmp (004011a0)
004010C5   jne         tell_me+4Ah (004010da)
15:           printf("Address of strcmp(): %0x\n", f);
004010C7   mov         ecx,dword ptr [ebp+8]
004010CA   push        ecx
004010CB   push        offset string "Address of strcmp(): %0x\n" (00422044)
004010D0   call        printf (00401120)
004010D5   add         esp,8
16:       else
004010D8   jmp         tell_me+5Bh (004010eb)
17:           printf("Function address: %p\n", f);
004010DA   mov         edx,dword ptr [ebp+8]
004010DD   push        edx
004010DE   push        offset string "Function address: %p\n" (00422028)
004010E3   call        printf (00401120)
004010E8   add         esp,8

离恨恰如春草,更行更远还生。
2010-03-13 15:21
hzh512
Rank: 9Rank: 9Rank: 9
等 级:蜘蛛侠
威 望:6
帖 子:234
专家分:1333
注 册:2009-6-5
收藏
得分:0 
本人做了一个实验:充分说明这属于c语言的语法问题,编译器编译分析时将func和*func视为同一种情况
int func(int x)
{}

int main()
{
    int (*f)(int x);
    f=func;
    f=*func;
    return 0;
 }

汇编代码:

.globl main
    .type    main, @function
main:
    leal    4(%esp), %ecx
    andl    $-16, %esp
    pushl    -4(%ecx)
    pushl    %ebp
    movl    %esp, %ebp
    pushl    %ecx
    subl    $20, %esp
    movl    $func, -8(%ebp)     对应 f=func
    movl    $func, -8(%ebp)     对应 f=*func
    addl    $20, %esp
    popl    %ecx
    popl    %ebp
    leal    -4(%ecx), %esp
    ret



[ 本帖最后由 hzh512 于 2010-3-13 15:32 编辑 ]

编程=用几种语言在某个或几个平台上通过抽象思维运用一系列算法来解决现实中问题的手段
2010-03-13 15:30
玩出来的代码
Rank: 11Rank: 11Rank: 11Rank: 11
来 自:河南新乡
等 级:贵宾
威 望:11
帖 子:742
专家分:2989
注 册:2009-10-12
收藏
得分:0 
回复 6楼 hzh512
不只是fun与*fun,你看一下&fun,也是一样的,都是同一地址这个我还真不知道怎么解释?

你怎么看的?

离恨恰如春草,更行更远还生。
2010-03-13 15:35
casio1374633
Rank: 1
等 级:新手上路
帖 子:22
专家分:0
注 册:2010-3-11
收藏
得分:0 
谢谢楼上几位,反汇编来得真直接.一下子就搞清楚了~~~谢谢了~~关于第二个问题的解答,我更倾向于4#的回答~~

谢谢楼上的各位.受教了

====================
各位都在啊,编辑的功夫又看到回帖了,看来都在奇怪这个部分,


[ 本帖最后由 casio1374633 于 2010-3-13 15:42 编辑 ]

静下心来,做点实事
2010-03-13 15:38
casio1374633
Rank: 1
等 级:新手上路
帖 子:22
专家分:0
注 册:2010-3-11
收藏
得分:0 
关于函数指针,还有个更奇怪的例子,如果各位有兴趣,帮忙看看这个:

#include <stdio.h>
void   f(void);
void   g(void);
void   h(void);
int main(void)
{
   (*f)();
   return 0;
}
void f(void)
{
   printf("Hello from f().\n");
   (((*g)))();
}
void g(void)
{
   printf("Hello from g().\n");
   (*(*(*h)))();  /*<---------谁能解释下?------*/
}
void h(void)
{
   printf("Hello from h().\n");
}

所指的那行,我自己测试过:使用h(), (*h), (*(*h)),(*(*(*h))),都可以.而且gdb观察都是同一个地址,各位能帮忙解释下吗?

静下心来,做点实事
2010-03-13 15:46
hzh512
Rank: 9Rank: 9Rank: 9
等 级:蜘蛛侠
威 望:6
帖 子:234
专家分:1333
注 册:2009-6-5
收藏
得分:0 
我在Linux写程序,所以我只说elf结构,其实在编译时,这些信息都忽略掉了(或者转化),同时使用gcc编译还可以生成调试信息,在调试信息中,gdb借助符号表,来对其进行识别(比如加行号、地址信息等等),你所说的情况,就是编译器生成调试信息时,被处理过的(在调试信息中,将他们解释成一个值),所以都是一个值。这个情况,你知道就行,其实他是编译器的容错处理,如果目前正学习语言阶段,没必要深究,等以后有余力了,在深究编译器的原理(特别是后端)。

编程=用几种语言在某个或几个平台上通过抽象思维运用一系列算法来解决现实中问题的手段
2010-03-14 10:02
快速回复:[貌似已解决]关于函数指针的2个问题,请帮帮忙.谢谢
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.027943 second(s), 7 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved