![]() |
Delphi-Version: 10 Seattle
Floating Point Exception oder Access Violation, je nach Schreibweise
Kann mir jemand folgendes Verhalten erklären?
Delphi-Quellcode:
Prozedur
uses System.Generics.Collections;
Delphi-Quellcode:
wirft eine Access Violation,
p1
Delphi-Quellcode:
hingegen eine Floating point invalid operation. Warum? Da ist doch kein Unterschied!
p2
Delphi-Quellcode:
procedure p1();
type TFloat = type Single; var values: TArray<TFloat>; begin values := [1.0, Single.Nan, 2.0]; TArray.Sort<TFloat>(values); end; procedure p2(); type TFloat = Single; var values: TArray<TFloat>; begin values := [1.0, Single.Nan, 2.0]; TArray.Sort<TFloat>(values); end; |
AW: Floating Point Exception oder Access Violation, je nach Schreibweise
Doch schon. Mit
Delphi-Quellcode:
deklarierst du ja einen neuen Strong-Type und nicht nur einen Alias. Vergleiche über TypInfo, RTTI, oder eben die Intrinsics im Zusammenhang mit der generischen
X = type Y
Delphi-Quellcode:
Methode werden hierbei dann keine Gleichheit mehr ergeben.
TArra<T>.Sort
Edit: Die generischen Container haben in Delphi für die meisten Standard-Typen spezifische Behandlungsroutinen. Dadurch, dass der RTL
Delphi-Quellcode:
bzw.
TFloat
Delphi-Quellcode:
unbekannt ist, wird hier dann vermutlich auf eine Fallbackroutine zurückgegriffen.
type Single
|
AW: Floating Point Exception oder Access Violation, je nach Schreibweise
Aber "Zugriffsverletzung" kommt mir dennoch etwas komisch vor. :gruebel:
|
AW: Floating Point Exception oder Access Violation, je nach Schreibweise
Ratet mal, wofür es den Debugger gibt. :angle:
Wie Zacherl bereits erwähnte, gehört dein neuer Typ nicht zu den bekannten "Default"-Typen, für Welche in Delphi passende Comparer existieren, also wird hier ganz einfach nur auf Type-Size gegangen und der Inhalt "Binär" verglichen.
Delphi-Quellcode:
Du mußt dir also selber einen Comparer erstellen, für solche Typen.
class procedure TArray.Sort<T>(var Values: array of T);
begin QuickSort<T>(Values, TComparer<T>.Default, Low(Values), High(Values)); end; class function TComparer<T>.Default: IComparer<T>; begin Result := IComparer<T>(_LookupVtableInfo(giComparer, TypeInfo(T), SizeOf(T))); end; class procedure TArray.QuickSort<T>(var Values: array of T; const Comparer: IComparer<T>; L, R: Integer); begin ... while Comparer.Compare(Values[I], pivot) < 0 do // Single function Compare_R4(Inst: Pointer; const Left, Right: Single): Integer; begin if Left < Right then // type Single function Compare_U4(Inst: Pointer; const Left, Right: Cardinal): Integer; begin if Left < Right then
Delphi-Quellcode:
TArray.Sort<TFloat>(Values, Comparer);
Die Zugriffsverletzung ist aber ein schwerwiegender Bug im QuickSort. :shock: Ich bin echt erstaunt, daß es nicht öfters knallt. Mit
Delphi-Quellcode:
knallt es schon im Compare, wegen des NAN und weil die FPU so eingestellt ist.
Single
> ![]() ![]() Bei
Delphi-Quellcode:
funktioniert der Vergleich, da "NAN" dort nicht behandelt wird, und es knallt im QuickSort.
type Single
Das erste
Delphi-Quellcode:
findet kein Ende und trifft hier "zufällig" irgendwann auf nicht zugewiesenen Speicher.
while Comparer.Compare(Values[I], pivot) < 0 do Inc(I);
Das Selbe wird man auch bei anderen Typen hinbekommen. Der BufferOverflow wird zum Glück abgefangen, da die Array-Grenzen im Anschluss geprüft werden und somit keine Schreibzugriffe außerhalb des Arrays auftreten. Es knallt also immer wenn im Array und davor oder dahinter auch kein fremder reservierter Speicher mit einem passenden Wert gefunden wird.
Delphi-Quellcode:
class procedure TArray.QuickSort<T>(var Values: array of T; const Comparer: IComparer<T>; L, R: Integer);
var I, J: Integer; pivot, temp: T; begin if (Length(Values) = 0) or ((R - L) <= 0) then Exit; repeat I := L; J := R; pivot := Values[L + (R - L) shr 1]; repeat while Comparer.Compare(Values[I], pivot) < 0 do Inc(I); while Comparer.Compare(Values[J], pivot) > 0 do Dec(J); Sehr eigenartig ist auch, dass in diesem Generic die Bereichsprüfung nicht funktioniert. :freak: >
Delphi-Quellcode:
bzw. in den Projektoptionen aktiviert
{$RANGECHECKS ON}
|
AW: Floating Point Exception oder Access Violation, je nach Schreibweise
|
AW: Floating Point Exception oder Access Violation, je nach Schreibweise
LOL, grade gefunden.
![]() Der Witz dabei ist, das du hier schon mit dem Bugfix arbeitest. (neuer Code, der ebenfalls nicht funktioniert) |
AW: Floating Point Exception oder Access Violation, je nach Schreibweise
Zitat:
|
AW: Floating Point Exception oder Access Violation, je nach Schreibweise
Danke für die Erklärung, jetzt verstehe ich es zumindest.
Und ja, ein Floating Point-Error wäre mir auf jeden Fall lieber als eine AV. PS: Dein Kommentar in ![]() ist wohl nochmal einen neuen Eintrag wert, die haben das Ticket danach einfach zu gemacht 8-) |
AW: Floating Point Exception oder Access Violation, je nach Schreibweise
Zitat:
Es gibt 'nen Bugfix ... du mußt ihn dir nur kaufen. Muß nur nochmal wer Testen, ob's wirklich geht. Zitat:
![]() |
Alle Zeitangaben in WEZ +1. Es ist jetzt 06:21 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz