zoukankan      html  css  js  c++  java
  • Delphi中实现变长函数笔记

        前面从网络中收藏加转贴了一部分关于变长参数函数的笔记。反正休闲没事,于是就专门的研究研究了如何用Delphi来实现类似于C语言中Printf这种可以传递任意多个参数的函数。这个实际上来说也不太难,只要俺们都熟悉函数的调用规则,那么就很容易了。实际上这个变长,总体上来说,应该是有迹可循的。那这个迹象在哪里,就是关键点了,也就是说,最主要的是要知道,这个函数到底传递了多少个参数。我们参看C的,printf和Windows的wsPrintf,都知道,实际上他里面都有一个Format的参数类型。有这个类型,就可以根据这个格式参数,来获取里面有多少个%d,%s,%f这样的匹配内容了,于是通过这个,我们就可以知道函数到底传递了多少个参数了。继而,俺们就可以从程序堆栈当中把这些参数一个个的给找出来,然后在俺们的函数中加以处理。那么这时候肯定就有人要问了,为什么参数是在堆栈中。。。。这个。。还是归于函数调用法则来说,最初制定的时候,有规定stdcall,pascal,以及Delphi默认的Register调用都是由程序自动管理堆栈,除此之外,还有一种调用方式就是cdecl这个方式,是由我们自己来平衡堆栈,自己管理的,而动态个数参数的函数,也就必须是这个cdecl的调用方式,这种调用方式,参数是按照从右向左的方式压入堆栈的,这样设计是有道理的,从右往左边压入,那么越早传入的参数就越晚被压入,那么我们就能够知道最有用的实际参数,比如此时如果进入到变长函数,那么我们就可以知道,当前堆栈的栈顶就是我们的现场,那么再网上递归,就是第一个参数了,也就是说[ebp+8]就是当前的第一个参数了。由此可以找到第二个参数,第三个参数。。。。。。

       所以,我们一定要在最初的参数中获取后面到底实际传递了多少个变体参数。然后才可以通过堆栈,一个个的找到,进而以函数来处理。

    说了这么多来举例实验一下。比如,写一个函数,需要获得传入的数字的和

    function GetSum(NumCount: integer{N1,N2: integer}): Integer;cdecl;
    asm
      {
      push ebp
      mov ebp,esp
      }
      mov ecx,[ebp + 8];//先获取第一个参数值,判断传递了几个参数
      //然后获取每个参数
      mov edx,12
      mov eax,0
    @@add:
      add eax,[ebp].edx
      add edx,4
      loop @@add
    end;
    

     然后调用方式:

    type
      VA_Sum = function(NumCount: integer{N1,N2}): Integer; cdecl varargs;
    
    var
      m: VA_Sum;
    begin
      m := GetSum;
      ShowMessage(inttostr(m(4,3,4,5,6)));
    end;
    

     在比如,连接字符串函数

    function ConStr(NumCount: integer{N1,N2}): string;cdecl;
    var
      st1: string;
      i: Integer;
    begin
      asm
        mov esi,16
      end;
      for i := 0 to NumCount - 1 do
      begin
        asm
          mov edi,[ebp].esi
          cmp edi,128
          jb @@char
          mov DWORD ptr st1,edi
          @@Char:
          add esi,4
        end;
        Result := Result + st1;
      end;
    end;
    

      调用方法

    type
      VA_ConStr = function(NumCount: integer{N1,N2}): string; cdecl varargs;
    
    var
      cstr: VA_ConStr;
    begin 
      cstr := constr;
      ShowMessage(cstr(3,'Test','不得闲','测试'));
    end;
    

      

    作者:不得闲
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原
    文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    可方便扩展的JIRA Rest Web API的封装调用
    小诗一首
    jxse2.6在jdk8下,JxtaMulticastSocket存在的问题
    http://blogs.msdn.com/b/pranavwagh/archive/2007/03/03/word-2007-file-seems-to-be-deleted-when-you-open-and-save-it-using-dsoframer.aspx
    how to javafx hide background header of a tableview?
    Styling FX Buttons with CSS
    2d网络游戏的延迟补偿(Lag compensation with networked 2D games)
    Fast-paced Multiplayer
    jspace2d——A free 2d multiplayer space shooter
    JXSE and Equinox Tutorial, Part 2
  • 原文地址:https://www.cnblogs.com/DxSoft/p/3028722.html
Copyright © 2011-2022 走看看