Thema: Delphi Frage zu MessageDlg

Einzelnen Beitrag anzeigen

Olli
(Gast)

n/a Beiträge
 
#16

Re: Frage zu MessageDlg

  Alt 3. Aug 2005, 13:03
Zitat von Luckie:
Und wie dann?
So wie dahead es vormacht.

Der Punkt ist folgender. Die Syntax mit dem PChar-Cast mag funktionieren (tut sie ja bekanntlich auch), sie mag sogar schneller sein (zumindest kann sie das unter bestimmten Umständen), aber @String[1] ist eine viel klarere Syntax.
Hier wird mit Compiler-Magic gespielt, ohne daß die meisten Leute wissen, was unter ihren Füßen vorgeht! Obwohl unnötig, entscheidet der Compiler über weitere Checks. Wie wir wissen, besitzen Strings einen Referenz- und einen Längenzähler.
Delphi-Quellcode:
type
      StrRec = record
        allocSiz: Longint;
        refCnt: Longint;
        length: Longint;
      end;
Da soviel am AnsiString und WideString und String "managed" abläuft, kann man fast sagen, daß es sich verhält wie bei einer Klasse in C++. Dort kann man Operatoren auch überladen. In Delphi geht dies nicht, also hat der Compiler eine explizite Unterstützung für Strings eingebaut. Die kann man ihm nehmen, indem man die System-Unit mal ein wenig ausmistet - aber das gehört hier nicht her.

Delphis Strings sind immer nullterminiert, sie sind also schonmal prinzipiell kompatibel mit PAnsiChar/PWideChar. Außerdem ist im Binärcode immer der Zeiger auf den Stringpuffer das Element, auf welches verwiesen wird. Die Offsets des o.g. Records werden also über negative Werte erreicht. Eigentlich ist also ein String in Delphi der Record von oben plus Zeiger auf den Puffer.

Und weil es so schön ist, habe ich mal folgende zwei Codeschnipsel in Delphi und im Disassembler verglichen:
Code:
var
  StringVar: string;
  dwSize: DWORD;
begin
  dwSize := MAX_PATH;
  SetLength(StringVar, MAX_PATH + 1);
  GetComputerName([color=red]@StringVar[1][/color], dwSize);
  Writeln(StringVar);
  Readln;
end.
Code:
var
  StringVar: string;
  dwSize: DWORD;
begin
  dwSize := MAX_PATH;
  SetLength(StringVar, MAX_PATH + 1);
  GetComputerName([color=red]PChar(StringVar)[/color], dwSize);
  Writeln(StringVar);
  Readln;
end.
Wie man im folgenden Code sieht, wird für jeden Typecast eine Funktion reingepappt. Wenn man sich die Funktionen anschaut, ist sogar die vom PChar-Cast (oft) schneller.
Code:
CODE:00408312                 mov    ds:dwSize, 260
CODE:0040831C                mov    eax, offset StringVar
CODE:00408321                 mov    edx, 261
CODE:00408326                 call   SetLength
CODE:0040832B                push   offset dwSize
CODE:00408330                 mov    eax, offset StringVar
[color=red]CODE:00408335                 call   @System@UniqueString$qqrr17System@AnsiString[/color]
CODE:0040833A                push   eax
CODE:0040833B                call   GetComputerNameA
CODE:00408340                 mov    eax, ds:ExceptionHandler
CODE:00408345                 mov    edx, ds:StringVar
CODE:0040834B                call   sub_4034A0
CODE:00408350                 call   _WRITELN
Code:
CODE:004082DE                mov    ds:dwSize, 260
CODE:004082E8                 mov    eax, offset StringVar
CODE:004082ED                mov    edx, 261
CODE:004082F2                 call   SetLength
CODE:004082F7                 push   offset dwSize
CODE:004082FC                mov    eax, ds:StringVar
[color=red]CODE:00408301                 call   @System@@LStrToPChar$qqrv[/color]
CODE:00408306                 push   eax
CODE:00408307                 call   GetComputerNameA
CODE:0040830C                mov    eax, ds:off_4092DC
CODE:00408311                 mov    edx, ds:StringVar
CODE:00408317                 call   sub_40346C
CODE:0040831C                call   _WRITELN
Was mich denn dann doch verwunderte, war daß auch bei der @String[1]-Syntax überhaupt eine extra Funktion aufgerufen wird. Diese wird benutzt um dem String, so er denn auf den Puffer eines anderen zugewiesenen Strings zeigt, eine eigene Kopie des eigentlichen Strings (i.e. Inhalt) zu verschaffen. Man muß sich also dazu klarmachen, daß ein String auch auf den Puffer eines ursprünglich anderen Strings zeigen kann. Bei einer Zuweisung wird dann der Zeiger zugewiesen, aber nicht der Puffer selbst kopiert. Das macht die Delphistrings natürlich äußerst effizient. Aber in unserem Fall verschafft es der klareren Syntax einen kleinen Nachteil, weil nämlich dieser Check erst dazwischengeschoben wird. Dieser Check wird offenbar forciert, wenn ich keinen Cast mache, sondern einen Pointer auf meinen String übergebe.

Fazit: Ich bleibe bei meiner klareren Syntax. Ihr dürft weiter PChar-Casts benutzen ... und dank obiger Erkenntnis sage ich auch nix böses mehr darüber ...

BTW: Vielleicht solltet ihr diesen Beitrag in die Codelib oder so schieben? Also splitten.
  Mit Zitat antworten Zitat