Byte Abfrage (Überlauf) Problem

Für Fehler in Lazarus, um diese von anderen verifizieren zu lassen.
Antworten
siro
Beiträge: 730
Registriert: Di 23. Aug 2016, 14:25
OS, Lazarus, FPC: Windows 11
CPU-Target: 64Bit
Wohnort: Berlin

Byte Abfrage (Überlauf) Problem

Beitrag von siro »

Hallo zusammen,
eventuell ist es heute zu warm, denn ich habe grade einen "Merkwürdige Erscheinung": :shock:
Ich arbeitet nur mit Bytes und provoziere "bewust" einen 8-Bit Überlauf bzw. Unterlauf.
55-254 ist normalerweise -199
Also Hexadezimale Schreibweise mit 16 Bit wäre das Ergebnis 0xFF39 und als Byte eben nur die 0x39 was wiederum der Zahl in Dezimal 57 entspricht.
Dann tätige ich einen Vergleich ob das Ergebnis größer 5 ist und hier habe ich je nach Codierung 2 unterschiedliche Ergebnisse.
In "C" hätte ich gesagt, das liegt an der "Integer Promotion" , aber in Pascal werden doch meines Wissens nach keine automatischen Umwandlungen getätigt.
Vielleicht hab ich aber wirklich grad einen Gedankenfehler. Könnt Ihr mich bitte aufklären.

Code: Alles auswählen

procedure TForm1.FormCreate(Sender: TObject);
var Timer,old,count,diff:Byte;
begin
  Timer := 55;
  Old   := 254;
  count := 5;
  diff  := Timer-old;
  if (Timer-old) > count then caption:='JA' else Caption:='NEIN';    // hier kommt NEIN raus
//  if (diff) > count then caption:='JA' else Caption:='NEIN';           // hier kommt JA raus
end;                                                                                                     



wenn ich das Caste :

Code: Alles auswählen

if Byte(Timer-old) > count then caption:='JA' else Caption:='NEIN';   

dann geht es wieder richtig.
Siro

sorrry vergessen:

Windows 10, 64 Bit
Lazarus V2.0.0
FPC 3.0.4
Grüße von Siro
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...

Socke
Lazarusforum e. V.
Beiträge: 3158
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Byte Abfrage (Überlauf) Problem

Beitrag von Socke »

Laut Dokumentation wird das Ergebnis auf die native Integer-Größe vergrößert; da du hier eine unsigned - unsigned Operation durchführst, wird auf signed gewechselt.
D.h. in dem Vergleich (Timer-old) > count sind die Datentypen NativeInt > Byte.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

siro
Beiträge: 730
Registriert: Di 23. Aug 2016, 14:25
OS, Lazarus, FPC: Windows 11
CPU-Target: 64Bit
Wohnort: Berlin

Re: Byte Abfrage (Überlauf) Problem

Beitrag von siro »

Okay, ich danke Dir Socke,
ich hab das schon so vermutet, da muss man natürlich aufpassen.
Habe leider immer wieder mit vielen Casting Problemen zu kämpfen, natürlich ganz besonders in "C"
Ich hätte gedacht wenn ich 2 Bytes voneinander abziehe, dann ist das Ergebnis auch wieder ein Byte,
aber es wird augenscheinlich erweitert auf den Nativen Int und der Vergleich schlägt damit fehl.
Also kein BUG, das soll so

Siro
Zuletzt geändert von siro am Mi 12. Jun 2019, 08:56, insgesamt 1-mal geändert.
Grüße von Siro
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...

Timm Thaler
Beiträge: 1224
Registriert: So 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded
CPU-Target: Raspberry Pi 3

Re: Byte Abfrage (Überlauf) Problem

Beitrag von Timm Thaler »

siro hat geschrieben:aber es wird augenscheinlich erweitert auf den Nativen Int und der Vergleich schlägt damit fehl.


Schlimmer noch: Auf verschiedenen Architekturen reagiert das unterschiedlich.

Schlimmer noch: Mit verschiedenen Optimierungsstufen kann sich das ändern.

Schlimmer noch: Mit einer neuer Version kann sich das ändern.*

=> Man macht sowas nicht!

siro
Beiträge: 730
Registriert: Di 23. Aug 2016, 14:25
OS, Lazarus, FPC: Windows 11
CPU-Target: 64Bit
Wohnort: Berlin

Re: Byte Abfrage (Überlauf) Problem

Beitrag von siro »

@Timm Thaler,
Du hast völlig recht, das sollte man möglichst (eigentlich "immer") vermeiden,
aber es gibt Situationen wo es SEHR nützlich sein kann.
Ich muss dann nur selbst aufpassen, dass ich die Typwandlung entsprechend richtig mache,
daher auch die entsprechenden Versuche.

Generell ist dass, was ich mir hab einfallen lassen, eh nur für Embedded Anwendungen sinnvoll.
Es geht um eine Resourcenschonende, präzise neue Delay Funktion. für Mikrosekunden und Millisekunden
Früher habe ich meine Delay_ms Funktion wie folgt implementiert:

Ein Timer wird auf 1 Millisekunde gestellt und löst dann einen Interrupt aus.
Im Interrupt wird eine DelayCount Variable runtergezählt, sofern sie noch nicht 0 ist.

Die Delay Funktion selbst setzt lediglich den DelayCount, welcher im Interrupt runtergezählt wird
und wartet dann bis sie 0 wird.

Code: Alles auswählen

 
procedure TimerInterrupt;
Begin
  if DelayCount > 0 then Dec(DelayCount);
end;
 
Procedure Delay_ms(ms:Word);
Begin
  DelayCount:=ms;
  While DelayCount > 0 do ;
end;
 

Die neue Variante benötigt KEINEN Interrupt mehr, ist wesentlich präziser und
der Timer kann auch noch für andere Dinge benutzt werden:
Der Timer zählt bei mir mit 100 MHz (10ns) 32 Bit hoch und läuft dann über und beginnt wieder bei 0
Bei 32 Bit tritt der Überlauf nach rund 43 Sekunden auf.
Meine "minimalistische" "C" Implementierung dafür sieht nun so aus:

Code: Alles auswählen

void Delay10ns(U32 count)
{ U32 old;
 
  old = LPC_T0TC;                          // aktuellen Timercount lesen
  while ((U32)(LPC_T0TC - old) < count) ;  // warten
}
 
#define Delay_us(us) Delay10ns((us)*100)
#define Delay_ms(ms) Delay10ns((ms)*100000)



Meine Delays laufen auf rund 1 Mikrosekunde genau benötigen eigentlich keine Hardware Resourcen,
weil, den Timer benutze ich auch noch für das Capturen von Pulsen, das läuft nämlich auch auf diesen Timer.

Da ich mir nicht sicher war, wie sich das mit der Berechnung beim Timerüberlauf verhält, habe ich VIEL getestet, bis es dann lief.
Um sicher zu gehen, habe ich die Überlauf Abfrage auch in Pascal codiert, erstmal mit 8 Bit, daher der genannte Code um es zu probieren
und da musste ich feststellen, dass es ohne Typecast nicht richtig läuft, zumindest nicht mit 8 Bit.

Siro

Jetzt bleibt doch noch eine Frage offen.
Wie würde man das in Pascal machen mit den #defines ?

Und sorry, es ist ja kein Bug, der Bug lag bei mir :oops: , eventuell kann man den Thread verschieben...
Grüße von Siro
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...

Socke
Lazarusforum e. V.
Beiträge: 3158
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Byte Abfrage (Überlauf) Problem

Beitrag von Socke »

siro hat geschrieben:Jetzt bleibt doch noch eine Frage offen.
Wie würde man das in Pascal machen mit den #defines ?

Du kannst inline-Funktionen verwenden:

Code: Alles auswählen

procedure Delay_us(us: NativeInt); inline;
begin
  Delay10ns((us)*100);
end;

Damit kann der Compiler den Code der Prozedur an die Aufrufstelle kopieren und bei Verwendung von Konstanten als Parametern die Multiplikation bereits beim Übersetzen auflösen.
Leider ist dies eine Kann-Funktionalität, die nur Warnungen erzeugt, wenn dies nicht umgesetzt werden kann.

Für eine definierte Deleay-Funktion mit festen Verhalten, müsste wohl eine Compiler-intrinische Funktion erstellt werden. D.h. der Compiler würde beim Aufruf einer bestimmten Funktion den benötigten Code selbst produzieren.
Hierzu hatte ich Juni 2016 auf der Mailing-Liste mal nachgefragt; Florian würde auch eine entsprechendes Intrinsic implementieren, wenn jemand die Anforderungen und den zu erzeugenden Code beisteuern kann (so seine damalige Aussage).
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

siro
Beiträge: 730
Registriert: Di 23. Aug 2016, 14:25
OS, Lazarus, FPC: Windows 11
CPU-Target: 64Bit
Wohnort: Berlin

Re: Byte Abfrage (Überlauf) Problem

Beitrag von siro »

Okay, Danke Dir Socke,
dann ist es ähnlch wie in "C" mit dem inline:
Der Compiler "darf" das, aber es ist nicht sichergestellt, dass er es auch tut.

Das der Compiler den Wert vorausberechnet, trotz Übergabeparameter, wäre schon SEHR Vorausschauend
und natürlich auch sinnvoll. Muss ich direkt mal ausprobieren.

Code: Alles auswählen

procedure Delay_us(us: NativeUInt); inline// NativeUInt (ohne Vorzeichen) 
begin
  Delay10ns((us)*100);
end;             
 
Aufruf: Delay_us(100);
 


Hier läd der Compiler tatsächlich gleich den Wert 10000 ins Register. Es wird auch kein Call erzeugt.
Kann ich also bestätigen, das macht er also sehr effizient.

Auch den Datentyp NativeInt kannte ich noch nicht, da muss ich in meinem Falle dann den Typ NativeUInt nehmen,
Sehr interessant, wieder was gelernt. Vielen Dank.

Siro
Grüße von Siro
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...

Socke
Lazarusforum e. V.
Beiträge: 3158
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Byte Abfrage (Überlauf) Problem

Beitrag von Socke »

siro hat geschrieben:dann ist es ähnlch wie in "C" mit dem inline:
Der Compiler "darf" das, aber es ist nicht sichergestellt, dass er es auch tut.

Der Compiler gibt Warn- und Debugmeldungen aus, wenn er eine Prozedur nicht per Inline übernehmen kann. Darin sind auch Informationen enthalten, warum er es nicht tut.

Bei inline müssen alle verwendeten Datentypen für Deklaration und auch lokale Variablen auch an der Aufrufstelle bekannt sein. Solltest du die Funktion in eine separatte Unit auslagern, empfiehlt sich hier der Interface-Bereich.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

Antworten