Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   EIntOverflow bei LongWord, nicht aber bei Word (https://www.delphipraxis.net/196521-eintoverflow-bei-longword-nicht-aber-bei-word.html)

Der schöne Günther 28. Mai 2018 17:11

Delphi-Version: 5

EIntOverflow bei LongWord, nicht aber bei Word
 
Warum?

Delphi-Quellcode:
{$OVERFLOWCHECKS ON}

procedure acceptDouble(const input: Double);
begin
   //
end;

procedure p();
var
   a, b: Word;
   x, y: LongWord;
begin
   a := 1000;
   b := 10000;
   acceptDouble(a-b);

   x := 1000;
   y := 10000;
   acceptDouble(x-y); // << EIntOverflow
end;

freimatz 28. Mai 2018 17:48

AW: EIntOverflow bei LongWord, nicht aber bei Word
 
Ich vermute mal bei Word macht er implizit eine Erweiterung auf Int64. Bei LongWord geht das nicht.
Kam keine Warnung?

himitsu 28. Mai 2018 18:15

AW: EIntOverflow bei LongWord, nicht aber bei Word
 
Bedenke auch, dass erst gerechnet und dann das Ergebnis konvertiert wird.

Das WORD wird wohl einfach nach INTEGER für die Berechnung gecastet.
Größer als SizeOf(Pointer) werden aber keine automatischen Castes vorgenommen.

Der schöne Günther 28. Mai 2018 18:19

AW: EIntOverflow bei LongWord, nicht aber bei Word
 
Zitat:

Zitat von freimatz (Beitrag 1403213)
Kam keine Warnung?

Nö.

Zitat:

Zitat von himitsu (Beitrag 1403217)
Größer als SizeOf(Pointer) werden aber keine automatischen Castes vorgenommen.

Aber es ist doch
Delphi-Quellcode:
SizeOf(Pointer) = SizeOf(LongWord)
?


PS: Verhalten bei Win32 und Win64 identisch.

himitsu 28. Mai 2018 18:41

AW: EIntOverflow bei LongWord, nicht aber bei Word
 
Ja, aber er würde danach größer sein.
Ich weiß jetzt nicht wie es im 64 Bit ist,
aber in 32 Bit wird maximal bis auf Größe der CPU-Register vergrößert.

Der schöne Günther 28. Mai 2018 18:46

AW: EIntOverflow bei LongWord, nicht aber bei Word
 
Verstehe ich nicht.

Das
Delphi-Quellcode:
-9000
nicht im Bereich eines LongWord (0..4 Mrd.) liegt ist mir klar, aber was wird denn hier vergrößert? Bei Word (0..65535) scheint er ja keine Probleme zu haben. Weshalb sollte er hier überhaupt auf einen signed Typen vergrößern?


Und wo wäre so etwas überhaupt dokumentiert?

Und wie komme ich jetzt überhaupt aus der Sache raus? Statt
Delphi-Quellcode:
acceptDouble(x-y)
ein
Delphi-Quellcode:
acceptDouble( (x*1.0) - (y*1.0))
wird ja wohl kaum die richtige Lösung sein...

himitsu 28. Mai 2018 19:02

AW: EIntOverflow bei LongWord, nicht aber bei Word
 
Bei dem Word wird der Compiler das einfach schon vorher casten, weil er 32 Bit halt am Liebsten hat.

Delphi-Quellcode:
   acceptDouble(Double(Integer(a) - Integer(b)));

   acceptDouble(Double(x - y));

Stevie 28. Mai 2018 19:08

AW: EIntOverflow bei LongWord, nicht aber bei Word
 
Weil overflow checking nicht richtig bei Datentypen funktioniert, die kleiner als 32bit sind, da die Rechenoperationen auf den 32bit Registern ausgeführt werden.

Versuch doch mal das:
Delphi-Quellcode:
a := High(Word);
a := a + 1;
Disassembly für die 2. Zeile:
Delphi-Quellcode:
0041A834 0FB745FE        movzx eax,[ebp-$02]
0041A838 83C001           add eax,$01
0041A83B 7105             jno $0041a842
0041A83D E836ACFEFF      call @IntOver
0041A842 668945FE        mov [ebp-$02],ax
jno ist "Jump if not overflow" - und hier gabs nunmal keinen Overflow, denn eax ist 32bit breit. Wenn er in Variable zurückschreibt, spricht er es allerdings nur als 16-bit an (ax).

Schreibst du allerdings statt
Delphi-Quellcode:
a := a + 1;
Delphi-Quellcode:
Inc(a);
, dann gibts nen overflow. :wall:
Denn das wird zu

Delphi-Quellcode:
0041A85C 668345FE01       add word ptr [ebp-$02],$01
0041A861 7305             jnb $0041a868
0041A863 E810ACFEFF      call @IntOver

Der schöne Günther 28. Mai 2018 19:15

AW: EIntOverflow bei LongWord, nicht aber bei Word
 
Ich kann mit Assembler nichts anfangen, glaube das jetzt aber (Weißkittel-Syndrom).

Ist das irgendwo dokumentiert? Wie verhält sich das auf Win64? Wie verhält sich das, sollte ich (Gott bewahre!) etwas auf iOS oder Android kompilieren wollen? Ist das immer noch alles 32 Bit?

Stevie 28. Mai 2018 19:20

AW: EIntOverflow bei LongWord, nicht aber bei Word
 
Zitat:

Zitat von Der schöne Günther (Beitrag 1403230)
Ich kann mit Assembler nichts anfangen, glaube das jetzt aber (Weißkittel-Syndrom).

Ist das irgendwo dokumentiert? Wie verhält sich das auf Win64? Wie verhält sich das, sollte ich (Gott bewahre!) etwas auf iOS oder Android kompilieren wollen? Ist das immer noch alles 32 Bit?

Es verhält sich irgendwie, bis es jemand als Bug reported und dann ist dieses Verhalten as designed :mrgreen:

Aber mal ehrlich - keine Ahnung.

Zacherl 28. Mai 2018 19:40

AW: EIntOverflow bei LongWord, nicht aber bei Word
 
Zitat:

Zitat von Der schöne Günther (Beitrag 1403230)
Wie verhält sich das auf Win64?

Ohne es jetzt verifiziert zu haben, wird dort vermutlich weiterhin mit den 32-Bit Registern gerechnet, solange man keine größeren Datentypen verwendet. X86-64 kann in den meisten Fällen ja beides bzw. benötigt sogar explizit ein 64-Bit promotion prefix (REX.W), um die Instructions von der standardmäßig 32-Bit Breite auf 64-Bit umzustellen.

Zitat:

Zitat von Der schöne Günther (Beitrag 1403230)
Wie verhält sich das, sollte ich (Gott bewahre!) etwas auf iOS oder Android kompilieren wollen? Ist das immer noch alles 32 Bit?

iOS ist definitiv tatsächlich immer 64-Bit seit einiger Zeit. Bei Android kann ich es dir nicht sagen .. wird vermutlich nicht einheitlich sein.

Der schöne Günther 28. Mai 2018 19:44

AW: EIntOverflow bei LongWord, nicht aber bei Word
 
Und sich wahrscheinlich alle paar Versionen ändern. Ab sofort traue ich keiner Addition und Subtraktion mehr und nehme für alles die größten Datentypen die ich finden kann.

Nicht wirklich, aber so in etwa.

gammatester 28. Mai 2018 20:03

AW: EIntOverflow bei LongWord, nicht aber bei Word
 
Für 16-Bit wird der 'falsche' Opcode benutzt (eigentlich der richtige aber wg. der 32-Bit Arithmetik wird in beiden Fällen das Overflow-Bit nicht gesetzt, also netto falscher Code)
Code:
Unit2.pas.38: a := 1000;
005CE68A 66C745FEE803     mov word ptr [ebp-$02],$03e8
Unit2.pas.39: b := 10000;
005CE690 66C745FC1027     mov word ptr [ebp-$04],$2710
Unit2.pas.40: acceptDouble(a-b);
005CE696 0FB745FE        movzx eax,[ebp-$02]
005CE69A 0FB755FC        movzx edx,[ebp-$04]
005CE69E 2BC2             sub eax,edx
005CE6A0 7105             jno $005ce6a7
005CE6A2 E80595E3FF      call @IntOver
Da OF nicht gesetzt ist, gibt's keinen Int-Overflow. Bei 32-Bitwird nicht OF getestet sondern CF, und das ist in beiden Fällen gesetzt.
Code:
Unit2.pas.44: acceptDouble(x-y); // << EIntOverflow
005CE6CA 8B45F8           mov eax,[ebp-$08]
005CE6CD 2B45F4           sub eax,[ebp-$0c]
005CE6D0 7305             jnb $005ce6d7
005CE6D2 E8D594E3FF       call @IntOver

Zacherl 28. Mai 2018 20:15

AW: EIntOverflow bei LongWord, nicht aber bei Word
 
Würde ich definitiv als Compiler-Bug einstufen.

Der schöne Günther 28. Mai 2018 21:02

AW: EIntOverflow bei LongWord, nicht aber bei Word
 
Das ist doch bestimmt seit 20 Jahren so. Den Bug behebt sicher keiner mehr.

Eine Warnung wäre bei so etwas vielleicht auch angebracht, aber wir wissen ja:
Zitat:

Zitat von MEissing (Beitrag 1273120)
Wenn Delphi (der Delphi-Compiler) alles testen würde, was eventuell schief gehen könnte, dann wären die Übersetzungszeiten länger.


samso 29. Mai 2018 07:54

AW: EIntOverflow bei LongWord, nicht aber bei Word
 
Bei
Delphi-Quellcode:
  a := 1000;
  b := 10000;
  dec(a, b);
  acceptDouble(a);
kommt die Überlaufmeldung. Dann wird auch korrekt mit 16 Bit Registern gerechnet.
Code:
0041C554 66C7051C484200E803 mov word ptr [$0042481c],$03e8
0041C55D 66C7051E4842001027 mov word ptr [$0042481e],$2710
0041C566 66A11E484200     mov ax,[$0042481e]
0041C56C 6629051C484200   sub [$0042481c],ax
0041C573 7305             jnb $0041c57a
0041C575 E84E8EFEFF      call @IntOver

himitsu 29. Mai 2018 11:29

AW: EIntOverflow bei LongWord, nicht aber bei Word
 
Nja, per se kann eine x86-CPU mit 16 und 8 Bit-Werten rechnen, aber wie bereits erkannt, castet Delphi oftmals schon vorher und die Überlaufprüfung spricht nicht an, wenn für die mathematischen Operationen dann die 32-Bit-Befehle verwendet werden.



Es gibt von Android noch 32 Bit OS, aber so wie es aussieht wird seit einiger Zeit von den meisten "größeren" Herstellerung scheinbar nur noch 64 Bit verwendet.
Der Vorteil eines OS mit nur noch einem Layer wäre ja eine kleinere Codebasis und dass Programme von der Bittigkeit dann überall laufen

Also 64 Bit-Apps welche in reinen 32 OS bekanntlich nicht laufen. Bzw. Es ist dann nicht nötig, dass dann unnötig viele Varianten eines Programms in einer APK liegen, wenn man überall die beste Performance haben will.

32 Bit ARM
64 Bit ARM
32 Bit Intel (x86)
64 Bit Intel (x86)

vv

64 Bit ARM
64 Bit Intel (x86)

In neueren Intel-Androids werden ja nun auch ARM-only-Apps (armeabi) ausgeführt.
Gut, das ist nicht sonderlich schnell, aber für kleine Apps, ohne große CPU-Auslastung, spart das nochmal Speicherplatz.



Uns interessiert es ja noch nicht, da Delphi aktuell eh nur 32 Bit für Android anbietet.
Und Intel von Delphi noch garnicht unterstützt wird. Da ist nur ein blöder ARM-Dummy drin, welcher eine Fehlermeldung anzeigt, mit dem Ergebnis, dass Delphi-Apps standardmäßig überall starten, aber selbst wenn das Android/Intel ARM emulieren kann, dort dennoch nichts läuft, weil der Emulator nicht anspringt, so lange der Dummy in der API rumgammelt. Und Dank des ARM-Dummy listet der PlayStore diese Apps für Intel-Geräte auf, obwohl sie dann doch nicht ausgeführt werden können.

KodeZwerg 29. Mai 2018 12:13

AW: EIntOverflow bei LongWord, nicht aber bei Word
 
@himitsu, ist das oft vorkommende "x68" ein Tippfehler für "x86" oder habe ich das falsch verstanden und kenne es einfach noch nicht?

himitsu 29. Mai 2018 12:52

AW: EIntOverflow bei LongWord, nicht aber bei Word
 
jupp

Stevie 29. Mai 2018 13:13

AW: EIntOverflow bei LongWord, nicht aber bei Word
 
Übrigens: LongWord ist nicht auf allen Plattformen 32bit - siehe http://docwiki.embarcadero.com/Libra...ystem.LongWord

Zitat:

Zitat von Der schöne Günther (Beitrag 1403242)
Das ist doch bestimmt seit 20 Jahren so. Den Bug behebt sicher keiner mehr.

Eine Warnung wäre bei so etwas vielleicht auch angebracht, aber wir wissen ja:
Zitat:

Zitat von MEissing (Beitrag 1273120)
Wenn Delphi (der Delphi-Compiler) alles testen würde, was eventuell schief gehen könnte, dann wären die Übersetzungszeiten länger.


Genau, wir alle wollen ja schließlich schnelle Buildzeiten, die dann potenziell fehlerhaften und langsame(re)n Code erzeugen... :roll:

himitsu 29. Mai 2018 13:20

AW: EIntOverflow bei LongWord, nicht aber bei Word
 
Das wird eh immer langser, von Version zu Version ... das bissl fällt dann auch nicht mehr auf, wenn es noch rein käme.


Es hab auch mehrere Versionen lang einen Bug, wo UInt64/LargeWord vei einigen Berechnungen als Int64 behandelt wurde.
Bissl was wird doch irgendwann repariert.


In 32 Bit ist Int64 und UInt64 emuliert und wird "langsam" über zwei Integer/Cardinal manuell berechnet.
Darum sträubt sich Delphi auch, Integer dahin automatisch etwas zu erweitern.

Der schöne Günther 29. Mai 2018 13:24

AW: EIntOverflow bei LongWord, nicht aber bei Word
 
Zitat:

Zitat von Stevie (Beitrag 1403308)
Genau, wir alle wollen ja schließlich schnelle Buildzeiten, die dann potenziell fehlerhaften und langsame(re)n Code erzeugen... :roll:

Richtig, denn ich steche Mitbewerber mit der geringeren Time-to-Market aus 8-)


Ernsthaft: Was lernen wir nun aus der Geschichte?

Muss ich es jetzt für alle Datentypen die es grade gibt durchprobieren und mir dann einen Zettel an den Monitor kleben "Vorsicht, bei Rechnen mit folgenden Typen..."


Es ist doch sicher irgendwo dokumentiert "Word mit Word verrechnen ergibt DWord", "DWord mit DWord verrechnen ergibt DWord", ...

KodeZwerg 29. Mai 2018 13:43

AW: EIntOverflow bei LongWord, nicht aber bei Word
 
Zitat:

Zitat von Der schöne Günther (Beitrag 1403312)
"DWord mit DWord verrechnen ergibt DWord", ...

Nicht ganz, DWORD mit DWORD kommt ein QWORD / DINT raus. (-9223372036854775808 bis 9223372036854775807)
Manche nennen es auch QUADWORD.

Bestimmt wird es in naher Zukunft auf OWORD/OCTOWORD o.ä. erweitert (128bit)

Der schöne Günther 29. Mai 2018 14:56

AW: EIntOverflow bei LongWord, nicht aber bei Word
 
Wenn dem so wäre gäbe es dieses Thema nicht denn dann hätte ich keinen Overflow gehabt.

himitsu 29. Mai 2018 15:24

AW: EIntOverflow bei LongWord, nicht aber bei Word
 
dword + word -> dword
Eventuell ist es auch manchmal bissl intelligenter und als Ergebnis wird dann das Größere der Beiden genommen.

Schlimm wird es, wenn man Int64 mit UInt64 verrechnen will, denn da gibt es aktuell nichts Größeres, in der CPU. (Fließkomme in FPU ausgenommen)



Mit MMX oder Dergleichen gibt es auch jetzt schon nativ 128 Bit.
[EDIT] Nee, MMX war 8*8, 4*16, 2*32 oder 1*64 Bit ... aber SIMD (SSE) kann 128 und teilweise sogar 256 Bit (AVX)

Stevie 29. Mai 2018 16:00

AW: EIntOverflow bei LongWord, nicht aber bei Word
 
Zitat:

Zitat von himitsu (Beitrag 1403326)
Schlimm wird es, wenn man Int64 mit UInt64 verrechnen will, denn da gibt es aktuell nichts Größeres, in der CPU.

Dafür gibts seit 10.2 zum Glück W1073

Zacherl 29. Mai 2018 16:04

AW: EIntOverflow bei LongWord, nicht aber bei Word
 
Ich glaube Günther geht es darum, dass seine
Delphi-Quellcode:
Word + Word
Expression nicht vor der Addition erweitert wurde (da ja schon erkennbar ist, dass der temporäre Wert direkt einem
Delphi-Quellcode:
Double
zugewiesen werden soll). Unter C printed folgender Code:
Code:
Word a = 1000;
Word b = 10000;
printf("%f", (double)(a - b))
übrigens "-9000.000000".

Stevie 29. Mai 2018 16:16

AW: EIntOverflow bei LongWord, nicht aber bei Word
 
Zitat:

Zitat von Zacherl (Beitrag 1403336)
Ich glaube Günther geht es darum, dass seine
Delphi-Quellcode:
Word + Word
Expression nicht vor der Addition erweitert wurde

Nope, es geht darum, dass je nach Größe des Ordinaltypes trotz
Delphi-Quellcode:
{$OVERFLOWCHECKS ON}
on keiner kommt.


Zitat:

Zitat von Zacherl (Beitrag 1403336)
Unter C printed folgender Code:
Code:
Word a = 1000;
Word b = 10000;
printf("%f", (double)(a - b))
übrigens "-9000.000000".

C schert sich auch nicht um Overflows.

Zacherl 29. Mai 2018 16:27

AW: EIntOverflow bei LongWord, nicht aber bei Word
 
Zitat:

Zitat von Stevie (Beitrag 1403343)
Zitat:

Zitat von Zacherl (Beitrag 1403336)
Ich glaube Günther geht es darum, dass seine
Delphi-Quellcode:
Word + Word
Expression nicht vor der Addition erweitert wurde

Nope, es geht darum, dass je nach Größe des Ordinaltypes trotz
Delphi-Quellcode:
{$OVERFLOWCHECKS ON}
on keiner kommt.

Sorry, das "nicht" war mir reingerutscht. Genau, das ist klar. Ohne eine Erweiterung auf 32-Bit würde es aber ja funktionieren. Oder halt wie oben irgendwo angemerkt über das Carry-Flag statt des Overflow-Flags.

Zitat:

Zitat von Stevie (Beitrag 1403343)
Zitat:

Zitat von Zacherl (Beitrag 1403336)
Unter C printed folgender Code:
Code:
Word a = 1000;
Word b = 10000;
printf("%f", (double)(a - b))
übrigens "-9000.000000".

C schert sich auch nicht um Overflows.

Macht Delphi im Grunde ja auch nicht. Der C-Code schiebt die Werte auch erst in ein 32-Bit Register, verrechnet sie und verwendet dann SSE/AVX für die Konvertierung nach Double. Caste ich statt nach Double in Word, wird einfach Truncated, was dann einem Überlauf gleichkommt. Wollte hiermit nur andeuten, dass die eigentliche Berechnung in Delphi schon soweit konform zu sein scheint. Lediglich der eigentliche Overflow-Check ist halt an der Stelle verbuggt.

Der schöne Günther 29. Mai 2018 18:00

AW: EIntOverflow bei LongWord, nicht aber bei Word
 
Eine ganz peinliche Frage, ich mache ja noch nicht lange Delphi :oops:

Ich sehe in Delphi keine Äquivalent zu C's
Delphi-Quellcode:
(double)(a - b)
außer vielleicht
Delphi-Quellcode:
a*1.0 - b
. Gibt es etwas besseres außer vielleicht einer zusätzlichen Variable der man dann
Delphi-Quellcode:
a
zuweist?

gammatester 29. Mai 2018 18:12

AW: EIntOverflow bei LongWord, nicht aber bei Word
 
Zitat:

Zitat von Der schöne Günther (Beitrag 1403372)
Ich sehe in Delphi keine Äquivalent zu C's
Delphi-Quellcode:
(double)(a - b)
außer vielleicht
Delphi-Quellcode:
a*1.0 - b
. Gibt es etwas besseres außer vielleicht einer zusätzlichen Variable der man dann
Delphi-Quellcode:
a
zuweist?

Delphi-Quellcode:
int(a) - int(b)
oder
Delphi-Quellcode:
int(a-b)
sollte auch funktionieren.

himitsu 29. Mai 2018 18:15

AW: EIntOverflow bei LongWord, nicht aber bei Word
 
Delphi-Quellcode:
CCast = PascalCast

(double)(a - b) = Double(a - b)

(double)a - b = Double(a) - b

(double)a - (double)b = Double(a) - Double(b)

(double)((integer)a - (integer)b) = Double(Integer(a) - Integer(b))

Der schöne Günther 29. Mai 2018 18:45

AW: EIntOverflow bei LongWord, nicht aber bei Word
 
Dann ist mein Delphi wohl kaputt, denn das kompiliert alles nicht. :cry:

Delphi-Quellcode:
procedure p();
var
   a:   LongWord;
   b:   LongWord;
   asFloat: Double;
begin
   a := 0;
   b := 1;
   asFloat := Double(a-b); // E2089 "Ungültige Typumwandlung"
end;

himitsu 29. Mai 2018 19:00

AW: EIntOverflow bei LongWord, nicht aber bei Word
 
Sehr eigenartig, der implizite Cast
Delphi-Quellcode:
asFloat := a-b;
funktioniert, aber der Explizite nicht. :gruebel:

Ich mache sowas selten/nie, drum bin ich jetzt auch überrascht, dass nichtmal ein
Delphi-Quellcode:
asFloat := Double(a);
geht.


Alle Zeitangaben in WEZ +1. Es ist jetzt 22:54 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 by Thomas Breitkreuz