源码网商城,靠谱的源码在线交易网站 我的订单 购物车 帮助

源码网商城

c语言:基于函数指针的两个示例分析

  • 时间:2020-07-29 03:39 编辑: 来源: 阅读:
  • 扫一扫,手机访问
摘要:c语言:基于函数指针的两个示例分析
[b]第一个: [/b]------------------------------------------------------
[u]复制代码[/u] 代码如下:
#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的位置指向同一位置? [b]后来别人通过反汇编发现的情况: [/b]============================================== 如下红色的几行,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 ================================================== 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======================================================= [b]第二个: [/b]--------------------------------------------------------------------------------------------
[u]复制代码[/u] 代码如下:
#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不是顺序执行的? ======================================================= [b]得到的解答: [/b]不同的编译器printf的函数参数进栈顺序不同,printf函数中的strcat可以看反汇编代码. 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 =============================================== 汇编直观而简单的说明了一些疑问.... 再说下gcc如何产生汇编代码: [b]1: gcc -S main.c 可以生成 [/b][b]2: gcc -c main.c 生成main.o [/b]objdump -S -D main.o > main.asm [b]我更倾向于第二种. [/b]
  • 全部评论(0)
联系客服
客服电话:
400-000-3129
微信版

扫一扫进微信版
返回顶部