zoukankan      html  css  js  c++  java
  • D7 array of const

     
    Delphi的Format函数大家都用得很多,第二个参数用着确实很方便。最近在数据库开发应用中需要自己创建一个带array of const参数的函数,对于常用的类型String,Integer,Pointer处理都没什么问题,但当用到Widestring类型时却出错,摸索了一上午,感觉获益良多。现在将问题、解决问题的思路、分析方法等一一道来,希望对诸君有所启发就达到了我写这篇文章的目的了!

    环境:Winxp + D7
    进入D7,在默认的新建工程中增加一过程Test(m: Array of const);
    procedure TForm1.test(m: array of const);
    var
    i, zero: Integer;
    s, t: String;
    c: Char;
    const
    sBoolean: Array [Boolean] of string = ('False', 'True');
    begin
    s := '';
    for i := 0 to High(m) do with m[i] do
        case VType of //写到这,按住Ctrl点击VType,打开System单元,将VType的枚举值贴到Case语句
          vtInteger:    (VInteger: Integer; VType: Byte);
          vtBoolean:    (VBoolean: Boolean);
          vtChar:       (VChar: Char);
          vtExtended:   (VExtended: PExtended);
          vtString:     (VString: PShortString);
          vtPointer:    (VPointer: Pointer);
          vtPChar:      (VPChar: PChar);
          vtObject:     (VObject: TObject);
          vtClass:      (VClass: TClass);
          vtWideChar:   (VWideChar: WideChar);
          vtPWideChar: (VPWideChar: PWideChar);
          vtAnsiString: (VAnsiString: Pointer);
          vtCurrency:   (VCurrency: PCurrency);
          vtVariant:    (VVariant: PVariant);
          vtInterface: (VInterface: Pointer);
          vtWideString: (VWideString: Pointer);
          vtInt64:      (VInt64: PInt64);
        end;
    Delete(s, 1, 1);
    Self.Caption := s;
    end;
    继续写,对各枚举值进行处理!这里作一下解释,Array of const正是由TVarRec类型组成的!
    请看Case of语句中的代码:
          vtInteger: s := s + ';' + IntToStr(VInteger);
          vtBoolean: s := s + ';' + sBoolean[VBoolean];
          vtChar: s := s + ';' + VChar;
          vtExtended: s := s + ';' + FloatToStr(VExtended^);
          vtString:
            if Assigned(VString) then begin
              t := VString^;
              s := s + ';' + t;
            end;
          vtPointer:
            if Assigned(VPointer) then
              s := Format('%S; Pointer: $%X ',[s, Integer(VPointer)]);
          vtPChar:
            if Assigned(VPChar) then begin
              t := VPChar^;
              s := s + ';' + t;
            end;
          vtObject:
            if Assigned(VObject) then
              s := Format('%S; $%X ClassName: %S ',[s, Integer(@VObject), VObject.ClassName]);
          vtClass:
            if Assigned(VClass) then
              s := Format('%S; Class Reference $%X - ClassName: %S ',[s, Integer(VClass), VClass.ClassName]);
          vtWideChar:
            begin
              t := VWideChar;
              s := s + ';' + t;
            end;
          vtPWideChar:
            if Assigned(VPWideChar) then begin
              t := VPWideChar^;
              s := s + ';' + t;
            end;
          vtAnsiString:
            if Assigned(VAnsiString) then begin
              t := PChar(VAnsiString);
              s := s + ';' + t;
            end;
          vtCurrency:
            if Assigned(VCurrency) then
              s := s + ';' + FloatToStr(VCurrency^);
          vtVariant:
            if Assigned(VVariant) then
              s := s + '; This is variant ';
          vtInterface:
            if Assigned(VInterface) then
              s := Format('%S; Interface: $%X',[s, Integer(VInterface)]);
          vtWideString:
            if Assigned(VWideString) then begin
              t := PWideString(VWideString)^;
              s := s + ';' + t;
            end;
          vtInt64:
            if Assigned(VInt64) then
              s := s + ';' + IntToStr(VInt64^);

    加上一按钮测试该函数
    procedure TForm1.Button1Click(Sender: TObject);
    var
    ws: WideString;
    begin
    ws := 'dda这是一个测试dfa';
    test([self, 'sdf', 2.3324, ws, TForm]);
    end;

    可以看到测试结果,变量ws的值没有显示出来,怎么办呢?

    我们可以看到WideString类型的值是指针,我们就从这里着手,在事件中添加一句:
    Button1.Caption := Format('$%X',[Integer(@ws)]);
    此句的作用是显示出ws的地址
    再在Test函数中也加上类似的语句,并注释掉无用的语句:
    //t := PWideString(VWideString)^;
    //s := s + ';' + t;
    s := s + ';' + Format('$%X',[Integer(VWideString)]);
    运行可看到二个地址不一样,说明Delphi对传入的参数数据作了复制
    因此将其强制转换成PWidechar应该可以,增加一变量声明
    w: WideString;

    w := PWideString(VWideString)^;
    s := s + ';' + w;
    但运行结果却只显示一个字符,别沮丧,已经摸到门道了!

    我们知道Format可以处理Widestring类型,这里只得到一个字符,说明字符被截断了。Delphi中的字符串是以#0结束,Widestring以二个#0结束,可以肯定w := PWideString(VWideString)^这句Delphi作转换时肯定将其默认作为AnsiString处理了。分析到这里已经可动手写下去了.....

    p: PByte;

            if Assigned(VWideString) then begin
              t := '';
              zero := 0;
              p := VWideString;
              repeat
                c := char(p^);
                inc(p);
                if c = #0 then
                  inc(zero) else
                  begin
                    zero := 0;
                    t := t + c;
                  end;
              until zero = 2;
              s := s + ';' + t;
            end;

    但是显示汉字却变成乱码了,而且处理也显得臃肿。到这里我们已经明白了,VWideString所指示的字符串是二字节宽字符串,而且Intel的字节顺序也是低位在前,高位在后。因此可用PWord进行处理!

    删除c,zero,w变量,p改成:
    p: PWord;

            if Assigned(VWideString) then begin
              t := '';
              p := VWideString;
              repeat
                t := t + widechar(p^);
                inc(p);
              until p^ = 0;
              s := s + ';' + t;
            end;
    可以看到核心代码已经很精练了,运行已经显示正常,汉字也无乱码了!至此我们似乎是大功告成了,但静下来想想,Delphi支持WideString到String的转换,它也应该有这样的处理代码。
    而且在循环中t := t + widechar(p^);语句处下一断点,运行到断点处,再打开CPU窗口,看到看似简洁的代码,单此一句,编译器都要给它加上一大堆处理代码。找到系统的字符串处理函数很有必要,经过在System.pas单元中搜索WideString,找到函数:procedure WideCharToStrVar(Source: PWideChar; var Dest: string);
    呵呵,这正是我们要的!!!
    现在循环语句及P变量都可删除了,代码我就省略了。

    function   MakeStr(const   Args:   array   of   const):   string;  
       
      const  
          BoolChars:   array[Boolean]   of   Char   =   ('F',   'T');  
      var  
          I:   Integer;  
      begin  
          Result   :=   '';  
          for   I   :=   0   to   High(Args)   do  
              with   Args[I]   do  
                  case   VType   of  
                      vtInteger:         Result   :=   Result   +   IntToStr(VInteger);  
                      vtBoolean:         Result   :=   Result   +   BoolChars[VBoolean];  
                      vtChar:               Result   :=   Result   +   VChar;  
                      vtExtended:       Result   :=   Result   +   FloatToStr(VExtended^);  
       
                      vtString:           Result   :=   Result   +   VString^;  
                      vtPChar:             Result   :=   Result   +   VPChar;  
                      vtObject:           Result   :=   Result   +   VObject.ClassName;  
                      vtClass:             Result   :=   Result   +   VClass.ClassName;  
                      vtAnsiString:   Result   :=   Result   +   string(VAnsiString);  
                      vtCurrency:       Result   :=   Result   +   CurrToStr(VCurrency^);  
                      vtVariant:         Result   :=   Result   +   string(VVariant^);  
                      vtInt64:             Result   :=   Result   +   IntToStr(VInt64^);  
       
              end;  
      end;  
       
      We   can   call   this   function   using   an   open   array   constructor   (see   Open   array   constructors).   For   example,  
       
      MakeStr(['test',   100,   '   ',   True,   3.14159,   TForm])  
       
      returns   the   string   "test100   T3.14159TForm".  

  • 相关阅读:
    iOS开发-UIScrollView原理
    关于tableView点击状态栏列表回到顶部的说明
    实用技术之bugly
    KVO你所不知道的"坑"
    iOS iPhone SDK 包含哪些东西?
    NSTime的全面认识
    四 数据结构与算法总结(一)
    三 数据结构 --数和二叉树
    二 线性表
    一 数据结构的概念,时间复杂度和空间复杂度
  • 原文地址:https://www.cnblogs.com/moonwind/p/4431537.html
Copyright © 2011-2022 走看看