首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 嵌入开发 > 汇编语言 >

关于printf不定参数怎么实现的有关问题

2012-03-28 
关于printf不定参数如何实现的问题小弟不才,最近在学习汇编,遇到关于printf不定参数如何实现的问题,深感

关于printf不定参数如何实现的问题
小弟不才,最近在学习汇编,遇到"关于printf不定参数如何实现"的问题,深感疑惑,看了printf函数的反汇编码还是不懂,望各位大虾,高人不吝赐教.
最好能解释下以下代码,尤其是0040d4b0处的 push offset string "%d,%d,%d"

遇到过同样问题的各位朋友也可以一起来讨论...

3: printf("%d,%d,%d",1,2,3,4);
0040D4A8 6A 04 push 4
0040D4AA 6A 03 push 3
0040D4AC 6A 02 push 2
0040D4AE 6A 01 push 1
0040D4B0 68 6C 2F 42 00 push offset string "%d,%d,%d" (00422f6c)
0040D4B5 E8 36 02 00 00 call printf (0040d6f0)
0040D4BA 83 C4 14 add esp,14h

printf:
0040D6F0 55 push ebp
0040D6F1 8B EC mov ebp,esp
0040D6F3 83 EC 0C sub esp,0Ch
0040D6F6 53 push ebx
0040D6F7 56 push esi
0040D6F8 57 push edi
0040D6F9 8D 45 0C lea eax,[ebp+0Ch]
0040D6FC 89 45 F4 mov dword ptr [arglist],eax
0040D6FF 83 7D 08 00 cmp dword ptr [format],0
0040D703 75 1E jne printf+33h (0040d723)
0040D705 68 7C 26 42 00 push offset string "format != NULL" (0042267c)
0040D70A 6A 00 push 0
0040D70C 6A 36 push 36h
0040D70E 68 9C 2F 42 00 push offset string "printf.c" (00422f9c)
0040D713 6A 02 push 2
0040D715 E8 66 3C FF FF call _CrtDbgReport (00401380)
0040D71A 83 C4 14 add esp,14h
0040D71D 83 F8 01 cmp eax,1
0040D720 75 01 jne printf+33h (0040d723)
0040D722 CC int 3
0040D723 33 C9 xor ecx,ecx
0040D725 85 C9 test ecx,ecx
0040D727 75 D6 jne printf+0Fh (0040d6ff)
0040D729 68 40 6F 42 00 push offset __iob+20h (00426f40)
0040D72E E8 9D FD FF FF call _stbuf (0040d4d0)
0040D733 83 C4 04 add esp,4
0040D736 89 45 FC mov dword ptr [buffing],eax
0040D739 8B 55 F4 mov edx,dword ptr [arglist]
0040D73C 52 push edx
0040D73D 8B 45 08 mov eax,dword ptr [format]
0040D740 50 push eax
0040D741 68 40 6F 42 00 push offset __iob+20h (00426f40)
0040D746 E8 45 C7 FF FF call _output (00409e90)
0040D74B 83 C4 0C add esp,0Ch
0040D74E 89 45 F8 mov dword ptr [retval],eax
0040D751 68 40 6F 42 00 push offset __iob+20h (00426f40)
0040D756 8B 4D FC mov ecx,dword ptr [buffing]
0040D759 51 push ecx
0040D75A E8 D1 FE FF FF call _ftbuf (0040d630)
0040D75F 83 C4 08 add esp,8
0040D762 8B 45 F8 mov eax,dword ptr [retval]
0040D765 5F pop edi
0040D766 5E pop esi
0040D767 5B pop ebx
0040D768 8B E5 mov esp,ebp
0040D76A 5D pop ebp
0040D76B C3 ret

[解决办法]
__cdecl的函数,参数由栈传递,最右边的先入栈,函数返回后由调用者平衡栈。

push offset string "%d,%d,%d" 就是把字符串的地址入栈……
[解决办法]
http://topic.csdn.net/t/20041124/09/3582660.html
[解决办法]
printf的实现很简单。
他依靠你的格式化字符串(那个"%d%d%d")来确定你传入的参数有几个,你的格式化字符串中匹配了多少个,他就认为是几个参数,不信你把这个格式化字符串和传入的参数数量弄做不匹配,之后程序就会因为堆栈而出错了。



可变参数的实现,其实是相当简单的。
因为在c和c++使用的调用方式中,除了__fastcall这种调用方式外,什么__stdcall,__cdecl,_thiscall,__pascal,__far等,其参数都是全部放在堆栈里面的。
而且是在堆栈里面按照从第一个参数在内存的最前面,第二个参数内存中在第二个参数的后面,所以可以像取得数组第一个元素的指针来当做数组头来使用索引访问后面的元素一样,第二个参数也可以依靠以第一个元素的地址作为指针数组的头,用索引来访问到它。那个帖子中有提到字节对齐,为什么会要字节对齐呢?
因为在32位机上面每次压参数肯定是压入一个4字节的数据,但有时候使用的参数是3字节的数据,如果你按照3字节来访问下一个堆栈中的数据(参数),当然会出错,因为实现中是没有按3来照顾你,实现中总是用4字节来压入的。
[解决办法]

探讨
... 你把这个格式化字符串和传入的参数数量弄做不匹配,之后程序就会因为堆栈而出错了 ...

[解决办法]
探讨
引用:
... 你把这个格式化字符串和传入的参数数量弄做不匹配,之后程序就会因为堆栈而出错了 ...
不会出错的吧。可用看楼主上面的代码,向 printf() 这类参数个数不定函数调用,堆栈的平衡是由调用者来进行的,而不是有 printf() 这样的函数来实现。调用者知道你实际压栈了多少个参数,所以知道该给 sp/esp 加上多少来进行平衡;而且,调用者统计压……

[解决办法]
探讨

引用:
... 你把这个格式化字符串和传入的参数数量弄做不匹配,之后程序就会因为堆栈而出错了 ...
不会出错的吧。可用看楼主上面的代码,向 printf() 这类参数个数不定函数调用,堆栈的平衡是由调用者来进行的,而不是有 printf() 这样的函数来实现。调用者知道你实际压栈了多少个参数,所以知道该给 sp/esp 加上多少来进行平衡;而且,调用者统计……

[解决办法]
都认为楼主的 printf("%d,%d,%d",1,2,3,4); 和上面的 printf ( "%d%d%d", 123); 会出错?
即使是在 TC2.0 下,用下面的代码,看运行结果,printf() 前后的 sp 都是一致的,尽管有些没有意义的额外输出。
C/C++ code
#include "stdio.h"#include "stdlib.h"void main (void){   int i;   asm mov ax, sp   asm mov i, ax   asm push sp   printf("sp=%04x%d%d%d\n",i);   asm pop ax   asm mov i, ax   printf("sp=%04x%d%d", i);}
[解决办法]
探讨
都认为楼主的 printf("%d,%d,%d",1,2,3,4); 和上面的 printf ( "%d%d%d", 123); 会出错?
即使是在 TC2.0 下,用下面的代码,看运行结果,printf() 前后的 sp 都是一致的,尽管有些没有意义的额外输出。

C/C++ code

#include "stdio.h"
#include "stdlib.h"

void m……

热点排行