2017-11-27 3 views
4

Was ist der grundlegende Unterschied zwischen IntToStr() und Integer.ToString() bei der Umwandlung einer Integer in eine string. Welcher ist schneller?Delphi-Compiler-Unterschied zwischen IntToStr() und Integer.ToString()?

var 
    VarInt: integer; 
    VarStr: string; 
begin 
    VarInt := 5; 
    VarStr := IntToStr(VarInt); 
    VarStr := VarInt.ToString; 
end; 
+2

Es gibt keinen Unterschied. "ToString" ist inline, daher erzeugt der Compiler im Wesentlichen das gleiche Ergebnis. – Victoria

+0

Es ist das gleiche Ergebnis und Geschwindigkeit, wenn ich mit 'VarStr: = (VarInt + 1) .ToString' –

+1

Ja. In beiden Fällen muss zuerst der Ausdruck 'VarInt + 1' ausgewertet werden. – Victoria

Antwort

9

Haftungsausschluss: Der folgende Text enthält Details, die nur für Delphi 10.2.1 gelten (und auch 10.2.2), die etwas gemacht zu haben, schlimmer über inlining und RVO scheint:

Der Code vom Compiler erzeugt unterscheidet sich tatsächlich (unabhängig von der Compiler-Version), wie Sie leicht sehen können, wenn Sie in das Disassemblierungsfenster schauen.

Lässt diese Routine nehmen:

procedure Main; 
var 
    i: Integer; 
    s: string; 
begin 
    i := 0; 
    s := IntToStr(i); 
    s := i.ToString; 
end; 

lassen Sie uns dies nun laufen und schauen in die Demontage-Fenster den Code der Compiler erzeugt zu überprüfen:

Dies ist, was Sie mit Delphi bekam 10.1:

Project1.dpr.14: s := IntToStr(i); 
00419810 8D55F8   lea edx,[ebp-$08] 
00419813 8B45FC   mov eax,[ebp-$04] 
00419816 E80DA4FFFF  call IntToStr 
Project1.dpr.15: s := i.ToString; 
0041981B 8D55F4   lea edx,[ebp-$0c] 
0041981E 8B45FC   mov eax,[ebp-$04] 
00419821 E802A4FFFF  call IntToStr 
00419826 8D45F8   lea eax,[ebp-$08] 
00419829 8B55F4   mov edx,[ebp-$0c] 
0041982C E843D2FEFF  call @UStrLAsg 

und das ist, was Sie mit 10.2.1 bekommen (und auch 10.2.2):

Project1.dpr.14: s := IntToStr(i); 
00419B04 8D55F8   lea edx,[ebp-$08] 
00419B07 8B45FC   mov eax,[ebp-$04] 
00419B0A E8C5A2FFFF  call IntToStr 
Project1.dpr.15: s := i.ToString; 
00419B0F 33C0    xor eax,eax 
00419B11 55    push ebp 
00419B12 68499B4100  push $00419b49 
00419B17 64FF30   push dword ptr fs:[eax] 
00419B1A 648920   mov fs:[eax],esp 
00419B1D 8D55F4   lea edx,[ebp-$0c] 
00419B20 8B45FC   mov eax,[ebp-$04] 
00419B23 E8ACA2FFFF  call IntToStr 
00419B28 8D45F8   lea eax,[ebp-$08] 
00419B2B 8B55F4   mov edx,[ebp-$0c] 
00419B2E E805D0FEFF  call @UStrLAsg 
00419B33 33C0    xor eax,eax 
00419B35 5A    pop edx 
00419B36 59    pop ecx 
00419B37 59    pop ecx 
00419B38 648910   mov fs:[eax],edx 
00419B3B 68509B4100  push $00419b50 
00419B40 8D45F4   lea eax,[ebp-$0c] 
00419B43 E8D4CCFEFF  call @UStrClr 
00419B48 C3    ret 
00419B49 E9CEC3FEFF  jmp @HandleFinally 
00419B4E EBF0    jmp $00419b40 

Jetzt ist die Millionen-Dollar-Frage, was ist die ganze Extra-Anleitung da ?!

Die zusätzlichen Anweisungen, die Sie in beiden Compilern sehen können, sind das Ergebnis der fehlenden so genannten Rückgabewertoptimierung. Wie Sie vielleicht wissen, behandelt der Compiler Ergebnisse von Funktionen, die einen verwalteten Typ (wie eine Zeichenfolge) aufweisen, als versteckten var-Parameter. Wenn der Compiler das Inlining ausführt, wird dieser Parameter nicht beseitigt und die Variable s wird direkt an die IntToStr übergeben, wie beim direkten Aufruf. Es reserviert vielmehr eine temporäre Variable, die es verwendet, um an die IntToStr übergeben und dann diese Variable an s (das ist die call @UStrLAsg Sie sehen dort 3 Zeilen nach dem IntToStr Anruf).

Wie oben erwähnt, scheint es eine Regression in 10.2 oder 10.2.1 zu geben, wo sie etwas über die temporäre Variablenbereinigung direkt nach dem Inline-Aufruf änderten (das sind die zusätzlichen Anweisungen davor und danach).

gemeldet als RSP-19439.

Fortsetzung folgt ...

+0

Interessanterweise, in Seattle, wenn ich mit Runtime-Paket verknüpfen, werden beide Anweisungen 100% identisch. Sonst bekomme ich die gleichen Ergebnisse wie 10.1 –

+0

Nein, sie nicht, schauen Sie sich die Adressen der beiden Anrufe. Die zweite ruft die Hilfsfunktion ohne Inlining auf. –

+0

Tatsächlich habe ich das vermisst. Aber entfernen Sie immer noch den UStrLAsg Teil. –

3

Es gibt keinen Unterschied.

Int.ToString ist wie so definiert:

function TIntHelper.ToString: string; inline; 
begin 
    Result := IntToStr(Self); 
end; 

Weil es inlined ist, wird es nur zu IntToStr(Int) übersetzen.

Die Methoden wurden hinzugefügt, um die Runtime Library (RTL) für Java- und C# -Programmierer gastfreundlicher zu machen. Das ist besonders relevant auf den mobilen Plattformen, auf denen Menschen wahrscheinlich Java ausgesetzt waren.

Ein großer Vorteil dabei ist, dass die Funktionen viel besser erkennbar sind. Sie können einfach VarInt. eingeben und die Auto-Vervollständigung zeigt Ihnen alle verfügbaren Optionen. Wenn Sie nichts über IntToStr wissen, ist es schon schwer es zu finden.

+0

Noch mehr mit String, .IndexOf, .SubString etc sind viel einfacher zu finden als Pos() und Copy() –