前段时间看了一阵子汇编,也算是对荒废的大学四年的祭奠,有的时候通过了解底层的东西, 对高级语言的理解还是灰常有帮助地。
c/c++中是存在可变长参数的,但那些仅仅是在编译阶段的可变长参数,运行时的调用参数状态则是固定的,
至于c++中的默认参数就根本和可变长不沾边儿了,只不过编译器做了个顺水人情而已
至于能不能在运行阶段在确定参数的个数呢,当然是可以的,用一些低级语言来做就很容易,例如汇编
下面就是实现一个对 c api sprintf 的改写 sprintf_x
代码:
;sprintfx.asm .386P .model flat public _sprintfx extern _sprintf:near ;C lib api sprintf ;TCHAR* pOutBuf, ;TCHAR* pszFormat, ;LPCTSTR* pszData, ;int x _sprintfx proc near push ebp mov ebp, esp mov esi, [ebp+10H] mov ecx, dword ptr [ebp+14H] LArgv: push dword ptr [esi] ;sprintf( *, *, argv[] sequenc reverse.... ); add ESI, 4 loop LArgv push [ebp+0CH] ;sprintf( *, szFormat, .... ); push [ebp+8] ;sprintf( szBuffer, *, .... ); call _sprintf mov esp, ebp ;balance the stack pop ebp ret _sprintfx endp
函数很简单,仅仅将传递的参数转发给了c api sprintf, 然后平衡堆栈, 结束
功能能实现,也得益于“C”调用约定,它是由调用者负责平衡堆栈,这样理论上 sprintf对参数的个数是没有限制的,只要返回后栈能够被正确恢复,程序就能正确运行
代码:
//sprintf_x.cpp extern "C" int sprintfx(TCHAR* pOutBuf, TCHAR* pszFormat, LPCTSTR* pszData, int x); _stdcall _sprintf_x(TCHAR* pOutBuf, TCHAR* pszFormat, LPCTSTR* pszData, int x) { if( !pOutBuf || !pszFormat || !pszData ) return -1; return sprintfx(pOutBuf, pszFormat, pszData, x); }
不知道前辈发过类似的帖子? 大家权当看着玩,莫笑 ;-)