Delphi中array of const應用

來源:互聯網
上載者:User
    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變數都可刪除了,代碼我就省略了。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.