Verschiedene Variablen auf gleiche Speicherstelle

Rund um die LCL und andere Komponenten

Re: Verschiedene Variablen auf gleiche Speicherstelle

Beitragvon Mathias » 5. Mär 2018, 22:48 Re: Verschiedene Variablen auf gleiche Speicherstelle

Wieso probierst du die erste Varianta nicht aus.
Ansonsten ein verschachtelten Record mit einem Dummy.
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 4260
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

Beitragvon wp_xyz » 6. Mär 2018, 00:32 Re: Verschiedene Variablen auf gleiche Speicherstelle

Timm Thaler hat geschrieben:Bösartige Frage: Ist es möglich, den Record so zu modifizieren, dass ich drei Bytewerte habe, aber nur aus 2en ein Word mache?

hh, mm, ss : uint8 // so sieht meine Uhrzeit aus, die ich von der RTC bekomme
hhmm // das ist mein Zeitwert, auf den ich vergleiche

Ich würde also gern "time" so auf hh,mm,ss mappen, dass im Highbyte hh, im Lowbyte mm stehen und ss nicht beachtet wird.

Code: Alles auswählen
type
  TTimeRec = packed record
    ss: uint8;
    case integer of
      0: (mm, hh: uint8);
      1: (time: utin16);
  end
wp_xyz
 
Beiträge: 2616
Registriert: 8. Apr 2011, 08:01

Beitragvon Mathias » 6. Mär 2018, 17:55 Re: Verschiedene Variablen auf gleiche Speicherstelle

@wp_xyz

Geniale Lösung. :shock:
Sowas bringt man in C++ nicht mal mit union hin.

Aber eins will ich doch mal wissen, für was ist der Bezeichner hinter case gut ?

Sowas wird auch kompiliert:
Code: Alles auswählen
  TTimeRec = packed record
    ss: uint8;
    case char of
      0: (mm, hh: uint8);
      1: (time: uint16);
  end;
  TTimeRec = packed record
    ss: uint8;
    case char of
      '0': (mm, hh: uint8);
      '1': (time: uint16);
  end;
 

Oder gar so etwas komisches:
Code: Alles auswählen
  TTimeRec = packed record
    ss: uint8;
    case Boolean of
      '0': (mm, hh: uint8);
      '=': (time: uint16);
      'x': (t: uint16);
  end;
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 4260
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

Beitragvon Socke » 6. Mär 2018, 18:14 Re: Verschiedene Variablen auf gleiche Speicherstelle

Die Typangabe ist immer dann sinnvoll, wenn du auch ein Feld dazu anlegst:
Code: Alles auswählen
  TTimeRec = packed record
    ss: uint8;
    case myvar: Boolean of
      '0': (mm, hh: uint8);
      '=': (time: uint16);
      'x': (t: uint16);
  end;

Die Werte haben dann aber immer noch nur dokumentarische Funktion. Gültig sind alle ordinale Typen (Char, Ganzzahl, Boolean); auch der Wertebereich wird nicht geprüft.

Der Inhalt des Feldes myvar muss dann aber immer noch durch den Entwickler gesetzt und geprüft werden.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein
Socke
 
Beiträge: 2539
Registriert: 22. Jul 2008, 18:27
Wohnort: Köln
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 8.1/Debian GNU/Linux/Raspbian/openSUSE | 
CPU-Target: 32bit x86 armhf
Nach oben

Beitragvon wp_xyz » 6. Mär 2018, 18:29 Re: Verschiedene Variablen auf gleiche Speicherstelle

Der im case angegebene Bezeichner ist Bestandteil des varianten Records. Je nach dessen Wert werden die Elemente des case-Teils entsprechend interpretiert, wobei der eigentliche Wert aber nicht geprüft wird.

Und daher ist mein Vorschlag auch Käse, weil sich die Byte-Folge nicht mit der Eingangssequenz überdeckt (ss mm hh). Richtig wöre, die Sekunden als Unterscheidungselement zu nehmen:
Code: Alles auswählen
type
  TTimeRec = packed record
    case ss:byte of
      0: (mm: byte; hh: byte);
      1: (time: word);
  end;   

Hier eine kleine Demo zur Verdeutlichung:
Code: Alles auswählen
program Project1;
 
{$mode objfpc}{$H+}
 
const
  s = '012345';
 
type
  TTimeRec = packed record
    case ss:byte of
      0: (mm: byte; hh: byte);
      1: (time: word);
  end;   
{
  TTimeRec = packed record
    ss: byte;
    case x:byte of
      0: (mm: byte; hh: byte);
      1: (time:word);
  end;
}

  PTimeRec = ^TTimeRec;
 
var
  t: TTimeRec;
  i: Integer;
begin
  t := PTimeRec(@s[1])^;
 
  for i := 1 to Length(s) do
    Write(ord(s[i]), ' ');
  WriteLn;
  WriteLn;
  WriteLn('      ss = ', t.ss);
//  WriteLn('       x = ', t.x);
  WriteLn('      mm = ', t.mm);
  Writeln('      hh = ', t.hh);
  WriteLn('Lo(time) = ', Lo(t.time));
  WriteLn('Hi(time) = ', Hi(t.time));
 
  WriteLn('SizeOf(TTimeRec) = ', SizeOf(TTimeRec));
 
  ReadLn;
end.
wp_xyz
 
Beiträge: 2616
Registriert: 8. Apr 2011, 08:01

Beitragvon Mathias » 6. Mär 2018, 20:29 Re: Verschiedene Variablen auf gleiche Speicherstelle

Und daher ist mein Vorschlag auch Käse, weil sich die Byte-Folge nicht mit der Eingangssequenz überdeckt (ss mm hh). Richtig wöre, die Sekunden als Unterscheidungselement zu nehmen:

Und was machst du, wen noch ms dazu kommt ?
Code: Alles auswählen
TTimeRec2 = packed record
  ms, ss: byte;
  case byte of
    0: (mm: byte; hh: byte);
    1: (time:word);
end;
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 4260
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

Beitragvon wp_xyz » 6. Mär 2018, 21:31 Re: Verschiedene Variablen auf gleiche Speicherstelle

Also, zunächst ist für 999 ms ein Byte zu klein. Nehmen wir ein Word. Dann wäre die Byteabfolge von low nach high: "xxxxssmmhh"(x = ms). Wenn dann ein Record darüber gelegt werden soll, der einmal die beiden Bytes mit "mm" und "hh" getrennt und einmal gemeinsam zugänglich macht, dann müsste dieser so deklariert werden:
Code: Alles auswählen
type
  TTimeRec = packed record
    ms: word;             // xxxx
    case ss: byte of      // ss
      0: (mm: byte;       // mm
          hh: byte);      // hh
      1: (time: word);    // mmhh
  end;

Eine Bemerkung aber noch: Welchen Sinn soll es haben, im Record-Element Minuten und Stunden als gemeinsame 16-bit Variable herauszuholen? Mit der Zahl kann man nichts machen, höchstens auf Gleichheit prüfen. Die ganze Übung erscheint mir relativ - hmmm - "wertfrei".
wp_xyz
 
Beiträge: 2616
Registriert: 8. Apr 2011, 08:01

Beitragvon Mathias » 6. Mär 2018, 21:42 Re: Verschiedene Variablen auf gleiche Speicherstelle

Also, zunächst ist für 999 ms ein Byte zu klein
Das stimmt, es könnte auch etwas anderes als Zeit-Einheiten sein.
Dann sieht diese Deklaration doch übersichtlicher aus:
Code: Alles auswählen
type
  TTimeRec = packed record
    ms: word;             // xxxx
    ss: Byte;             // ss
    case byte of
      0: (mm: byte;       // mm
          hh: byte);      // hh
      1: (time: word);    // mmhh
  end;

Eine Bemerkung aber noch: Welchen Sinn soll es haben, im Record-Element Minuten und Stunden als gemeinsame 16-bit Variable herauszuholen?

Egal um Zeit oder sonst was, es ging mir nur drum, wie man so etwas deklariert,
Aber irgendwie ist das mit case ordinal doch etwas merkwürdig gelöst. 8)
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 4260
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

Beitragvon Timm Thaler » 6. Mär 2018, 22:03 Re: Verschiedene Variablen auf gleiche Speicherstelle

wp_xyz hat geschrieben:Welchen Sinn soll es haben, im Record-Element Minuten und Stunden als gemeinsame 16-bit Variable herauszuholen? Mit der Zahl kann man nichts machen, höchstens auf Gleichheit prüfen. Die ganze Übung erscheint mir relativ - hmmm - "wertfrei".


Genau DAS ist der Sinn. Ich habe ein Array von hh:mm Werten, gespeichert als Packed BCD. Das durchsuche ich auf die aktuelle Zeit, um Ereignisse auszulösen.

Warum Packed BCD? Weil die RTC (DS1307) das so liefert. Weil man das prima in Ziffern wandeln kann (nur shift, and und add). Weil man prima damit rechnen kann, ohne mit mul und div rummachen zu müssen. Weil man prima darauf vergleichen kann (die ungenutzten Zwischenwerte stören dabei nicht). Klar könnte ich die Zeit von der RTC erstmal in Sekunden wandeln (3600 * hh + 60 * mm + ss). Wenn ich dann daraus die hh und mm brauche, muss ich durch 60 teilen. Da ein Tag nicht in 16 Bit passt, brauche ich 32bit-Operationen.

Wenn ich auf hh und mm einzeln habe, ist ein größer / kleiner Vergleich schwierig, weil er mit Übertrag erfolgen muss. Also muss ich entweder die Zeit zusammenrechnen - oder das halt direkt in ein Word packen. Der Vergleich ist dann ein cp und cpc auf dem AVR.

Die Verwendung von Packed BCD als Zeit scheint erstmal antiquiert, aber auf einem Mikrocontroller ist das tatsächlich praktisch.
Timm Thaler
 
Beiträge: 670
Registriert: 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
Nach oben

Beitragvon wp_xyz » 6. Mär 2018, 22:15 Re: Verschiedene Variablen auf gleiche Speicherstelle

Mathias hat geschrieben:
Code: Alles auswählen
type
  TTimeRec = packed record
    ms: word;             // xxxx
    ss: Byte;             // ss
    case byte of
      0: (mm: byte;       // mm
          hh: byte);      // hh
      1: (time: word);    // mmhh


Nur zur Sicherstellung: Das ist nicht richtig, das Feld ss muss weg, weil auch das unter "case" erwähnte Byte ebenfalls im Stream auftaucht. Dein Record ist 2 (ms) + 1 (ss) + 1 (case byte) + 2 (mmhh) = 6 Bytes lang, meiner nur 5. Wiegesagt, die nach "case" genannten Werte 0 oder 1 sind ohne Bedeutung, es ist nur wichtig, dass sie unterschiedlich sind.
wp_xyz
 
Beiträge: 2616
Registriert: 8. Apr 2011, 08:01

Beitragvon Socke » 6. Mär 2018, 22:25 Re: Verschiedene Variablen auf gleiche Speicherstelle

wp_xyz hat geschrieben:Nur zur Sicherstellung: Das ist nicht richtig, das Feld ss muss weg, weil auch das unter "case" erwähnte Byte ebenfalls im Stream auftaucht. Dein Record ist 2 (ms) + 1 (ss) + 1 (case byte) + 2 (mmhh) = 6 Bytes lang, meiner nur 5. Wiegesagt, die nach "case" genannten Werte 0 oder 1 sind ohne Bedeutung, es ist nur wichtig, dass sie unterschiedlich sind.

Dann hab ich hier einen Compilerfehler (3.1.1, rev. 37316)?
Code: Alles auswählen
program Project1;
 
type
  TTimeRec1 = packed record
    ms: word;             // xxxx
    ss: byte;             // ss
    case byte of
      0: (mm: byte;       // mm
          hh: byte);      // hh
      1: (time: word);    // mmhh
  end;
 
  TTimeRec2 = packed record
    ms: word;             // xxxx
    case ss: byte of      // ss
      0: (mm: byte;       // mm
          hh: byte);      // hh
      1: (time: word);    // mmhh
  end;
 
begin
  WriteLn('TTimeRec1', ' ', SizeOf(TTimeRec1));
  WriteLn('TTimeRec2', ' ', SizeOf(TTimeRec2));
end.

Ausgabe:
Code: Alles auswählen
TTimeRec1 5
TTimeRec2 5


Die Dokumentation kann man nach deinem Verständnis lesen: das Feld ist immer da, aber es gibt keinen Zugriff darauf, wenn man keinen Namen angibt.
FPC Language Reference Guide, Records hat geschrieben:The optional identifier in the case statement serves to access the tag field value, which otherwise would be invisible to the programmer. It can be used to see which variant is active at a certain time. In effect, it introduces a new field in the record.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein
Socke
 
Beiträge: 2539
Registriert: 22. Jul 2008, 18:27
Wohnort: Köln
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 8.1/Debian GNU/Linux/Raspbian/openSUSE | 
CPU-Target: 32bit x86 armhf
Nach oben

Beitragvon wp_xyz » 6. Mär 2018, 22:59 Re: Verschiedene Variablen auf gleiche Speicherstelle

Ah! Mit fpc 3.04 sehe ich das auch, und auch mit Delphi.

Das wusste ich nicht - offenbar wird das case-Byte nur mitgezählt, wenn es benannt ist. Dadurch wird das ganze wieder viel lesbarer.
wp_xyz
 
Beiträge: 2616
Registriert: 8. Apr 2011, 08:01

Beitragvon Mathias » 7. Mär 2018, 17:46 Re: Verschiedene Variablen auf gleiche Speicherstelle

Das wusste ich nicht - offenbar wird das case-Byte nur mitgezählt, wenn es benannt ist. Dadurch wird das ganze wieder viel lesbarer.

Alles andere würde auch keine Sinn machen. Das mit dem case ist nach meiner Meinung etwas unglücklich in Pascal gelöst. Vor allem der Bezeichner zwischen case und of.
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 4260
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

Beitragvon Timm Thaler » 11. Mär 2018, 21:25 Re: Verschiedene Variablen auf gleiche Speicherstelle

Also erstens: Funktioniert auf dem AVR hervorragend und mit optimalem Code.

Und noch eine kleine Frage: Kann ich auch nach dem Case noch weitere Variablen in den Record einfügen? Wenn ich einfach welche dazuschreibe, meckert der Compiler, weil er den Case fortsetzen will. Wenn ich den Case mit End beende, wird der Record geschlossen.

Nicht dass ich das jetzt bräuchte, aber es würde mich um des Prinzips willen interessieren.
Timm Thaler
 
Beiträge: 670
Registriert: 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
Nach oben

Beitragvon wp_xyz » 11. Mär 2018, 21:52 Re: Verschiedene Variablen auf gleiche Speicherstelle

Timm Thaler hat geschrieben:Und noch eine kleine Frage: Kann ich auch nach dem Case noch weitere Variablen in den Record einfügen?

Ja, aber die müssen VOR dem CASE stehen, oder anders herum ausgedrückt: CASE muss das letzte Element des Record sein.
https://de.wikibooks.org/wiki/Programmi ... in_Records
wp_xyz
 
Beiträge: 2616
Registriert: 8. Apr 2011, 08:01

» Weitere Beiträge siehe nächste Seite »
VorherigeNächste

Zurück zu Komponenten und Packages



Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 2 Gäste

porpoises-institution
accuracy-worried