【 声明:版权所有,欢迎转载,请勿用于商业用途。  联系信箱:feixiaoxing @163.com】

在编写代码的时候我们都会自己重新定义一个打印函数,为什么要这样呢?我想主要原因还是为了定义其中的打印开关。如果打开了开关,我们当然可以看到很多的打印信息,但是如果不需要这些信息,我们就可以关上这些开关,所以一般的打印函数函数都是可以自己定义的。

#include <stdio.h>
#include <windows.h>void XiaoxingPrintf(char* str, ...)
{char buffer[64];va_list va;va_start(va, str);vsprintf(buffer, str, va);va_end(va);printf("%s\n", buffer);
}int main(int argc, char* argv[])
{XiaoxingPrintf(" argc = %d, &argv = 0x%x\n", argc, &argc);return 1;
}

上面的这段代码其实也很平常,看上去没有什么特别之处,但是我们想知道,这个va究竟是个什么东西?不妨可以反汇编看一下,

7:    void XiaoxingPrintf(char* str, ...)
8:    {
0040D430   push        ebp
0040D431   mov         ebp,esp
0040D433   sub         esp,84h
0040D439   push        ebx
0040D43A   push        esi
0040D43B   push        edi
0040D43C   lea         edi,[ebp-84h]
0040D442   mov         ecx,21h
0040D447   mov         eax,0CCCCCCCCh
0040D44C   rep stos    dword ptr [edi]
9:        char buffer[64];
10:       va_list va;
11:
12:       va_start(va, str);
0040D44E   lea         eax,[ebp+0Ch]
0040D451   mov         dword ptr [ebp-44h],eax
13:       vsprintf(buffer, str, va);
0040D454   mov         ecx,dword ptr [ebp-44h]
0040D457   push        ecx
0040D458   mov         edx,dword ptr [ebp+8]
0040D45B   push        edx
0040D45C   lea         eax,[ebp-40h]
0040D45F   push        eax
0040D460   call        vsprintf (0040d750)
0040D465   add         esp,0Ch
14:       va_end(va);
0040D468   mov         dword ptr [ebp-44h],0
15:
16:       printf("%s\n", buffer);
0040D46F   lea         ecx,[ebp-40h]
0040D472   push        ecx
0040D473   push        offset string "%s\n" (0042201c)
0040D478   call        printf (0040d850)
0040D47D   add         esp,8
17:   }
0040D480   pop         edi
0040D481   pop         esi
0040D482   pop         ebx
0040D483   add         esp,84h
0040D489   cmp         ebp,esp
0040D48B   call        __chkesp (0040d710)
0040D490   mov         esp,ebp
0040D492   pop         ebp
0040D493   ret

上面的汇编代码很多,其实有用的信息并不多。首先我们看va_start这一句话,好像做的事情很简单,就是把ebp+0xc给了va,va本身占用了四个字节,也就是位于[ebp-44h]的位置。那么最后的va_end呢,也不复杂,也就是把[ebp-44h]的位置清零了一下。但是可虑到这里的va是一个临时变量,是否清零其实意义不大。那么,这里的ebp+0xc是什么意思呢?首先我们看到,ebp上面的数值是原来push ebp的数值,ebp+4是函数的返回地址,ebp+8是str的地址,那么很明显,ebp+0xc就是第二个参数的地址。所以,我们可以对这个打印函数稍微改造一下,

void XiaoxingPrintf(char* str, ...)
{char buffer[64];vsprintf(buffer, str, &str + 1);printf("%s\n", buffer);
}

同样一个函数,三句话就可以搞定了。不再需要记住那么多头文件和数据类型。当然,这背后需要你对函数堆栈、参数地址、ebp和esp理解得比较深刻和具体了。

随想录(由自定义打印函数想到的)相关推荐

  1. swift5优秀打印函数自定义

    swift5优秀打印函数自定义 func LJLog<T>(message: T,file: String = #file,funcName: String=#function,lineN ...

  2. C语言自定义打印宏函数

    在调试大型项目中,打印信息分级和指出打印所在处,更方便于解决问题.查阅网上的文章并加上自己的修改,实现了个简单的宏打印函数来达到目的.宏函数实现在头文件中,加上了打印级别来控制打印是否输出,打印级别的 ...

  3. 自定义条件查询_数据查询不止有vlookup函数,自定义zlookup函数查询操作更高效...

    Excel数据查询,相信大家首先会想到vlookup函数.毋庸置疑vlookup函数在Excel数据查询中作用是非常的强大.但是它也有一些不能实现的数据查询. 如上图所示,我们需要根据人员的出现次数, ...

  4. 【第3版emWin教程】第55章 emWin6.x按钮Button控件自定义回调函数,实现各种按钮效果

    教程不断更新中:链接 第55章       emWin6.x按钮Button控件自定义回调函数,实现各种按钮效果 本章节为大家讲解按钮控件自定义回调函数,通过其回调函数就可以实现各种按钮效果.这方面的 ...

  5. 在ARM芯片中使用打印函数总结

    ** 在ARM芯片中使用打印函数总结: ** 在使用的stdio.h库可以找到对应的函数原型 1.printf函数 原型:#pragma __printf_args extern _ARMABI in ...

  6. layui js 自定义打印功能实现

    打印功能的实现往往是新建一个页面,然后在新建页面中画出你想要的效果,然后调用浏览器的打印功能进行打印 项目依赖: layui jquery 记得换layui和jquery引入路径 完整项目代码: &l ...

  7. 【Python】自定义排序函数

    目录 自定义排序函数 实现忽略大小写排序的算法 剑指 Offer 45. 把数组排成最小的数 python 自定义排序函数 自定义排序函数 Python内置的 sorted()函数可对list进行排序 ...

  8. 【FFmpeg】自定义回调函数处理AVIOContext中的数据

    1.简述 AVIOContext是FFmpeg管理输入输出数据的结构体,它的成员变量有指向数据的指针.大小以及处理数据的回调函数指针等等.如果使用avio_open或avio_open2来创建,它会根 ...

  9. 史上自定义 JavaScript 函数Top 10

    史上自定义 JavaScript 函数Top 10 http://www.dustindiaz.com/top-ten-javascript/     发布:wpulog | 发布时间: 2010年4 ...

最新文章

  1. android调用文件管理打开某个路径,安卓 通过intent调用系统文件管理器打开指定路径目录...
  2. flannel源码分析--LookupExtIface
  3. 【CentOS Linux 7】实验7【FTP服务器配置管理】
  4. 设计模式(命令模式)
  5. gRPC-微服务间通信实践
  6. 计算机网络课程设计之电子邮件客户端程序设计与实现
  7. 华为公司参加2006 CCBN广电信息网络展览会
  8. Java文件流字节流和字符流的区别
  9. 《Effective Ruby:改善Ruby程序的48条建议》一第2条:所有对象的值都可能为nil
  10. 脑图管理项目很方便清晰!
  11. 把mysql数据展示为图表_怎么从数据库中调出数据并生成动态图表?
  12. 实验二、人工智能:产生式系统(动物识别系统)
  13. atv320说明书_ATV320U30N4B 施耐德 ATV320通用变频器 说明书
  14. c语言猜拳游戏石头剪刀布,模拟剪刀石头布猜拳游戏
  15. 京东零售数据仓库演进之路
  16. U²-Net:使用显著性物体检测来生成真实的铅笔肖像画
  17. 《薛兆丰经济学讲义》的118个思考题
  18. 【ArangoDB 介绍】
  19. Tuscany 的说明
  20. android网络下载图片并且显示在图库中

热门文章

  1. IIS 部署WCF时遇到这么个错:
  2. 12C 新特性--全库缓存
  3. bash shell简介及变量
  4. 把杀某程序封装成sh
  5. 防御暴力破解SSH攻击
  6. 图片不存在显示默认图片
  7. iOS之NSURLConnection详解(2)
  8. dz3.0数据库操作函数分析说明
  9. python 程序bug解决方案
  10. C# ActiveX开发部署更新