Programmiersprache Pascal

Variante Records

Mit varianten Records eröffnen sich in Pascal Variante Records lassen in Pascal ähliche Möglichkeiten (und Risiken) zu wie Unions in C bzw. C++ oder wie die EQUIVALENCE-Anweisung in Fortran.

Bemerkung:
In der Nachfolgesprache Oberon hat Pascal-Entwickler N. Wirth die varianten Records "abgeschafft".


Variante Records erlauben den Einbau von Komponenten, deren Typ abhängig ist vom Wert einer anderen Komponente, die als Selektor bezeichnet wird.
Der Selektor muß einen ordinalen Datentyp besitzen !

Ein Datentyp für variante Records wird wie folgt vereinbart:

  TYPE name = RECORD
                CASE selektor: typ OF
                  konstante_1: ( komponente_11; ...; komponente_1n1 );
                  ...
                  konstante_m: ( komponente_m1; ...; komponente_mnm )
              END;
komponente steht wie bereits oben notiert für eine der beiden folgenden Varianten:
  komponenten_name : typ;
  komponenten_name_1, ..., komponenten_name_k : typ;
Der Selektor ist, abgesehen von seiner Schaltfunktion, eine Komponente des Records und wird bei Bezugnahmen wie alle anderen Komponenten angesprochen.

Die Komponentengruppe ( komponente_1; ...; komponente_n ) darf leer sein: ( ).
Die Anzahl der Komponenten pro Gruppe darf zwischen den verschiedenen Varianten variieren.

Für typ darf in einigen Pascal-Versionen kein anonymer Datentyp, sondern nur ein Typbezeichner angegeben werden.

Beispiel:

  TYPE koordinat = RECORD
                     CASE typ : (karthesisch, polar) OF
                       karthesisch : ( x, y : REAL );
                       polar : ( r : REAL; phi : INTEGER );
                   END;

  VAR pkt1, pkt2 : koordinat;

  pkt1.typ := karthesisch; 
  pkt1.x   := 0.5; 
  pkt1.y   := 1.2;

  pkt2.typ := polar;
  pkt2.r   := 0.8;
  pkt2.phi := 90;
Bemerkung:
Diese Variante wird nicht von allen Pascal-Systemen unterstützt.
Im Interesse der Portabilität sollte auf ihre Anwendung verzichtet werden.

Die Besonderheit beim varianten Record besteht darin, daß die alternativen Komponentengruppen den gleichen Speicherplatz belegen !

Achtung:
Es muß damit gerechnet werden, daß unabhängig vom jeweiligen Wert des Selektors auf alle Varianten zugegriffen werden kann.
Variante Records sind deshalb anfällig gegenüber Fehlern.


Ein varianter Record kann auch wie folgt vereinbart werden:

  TYPE typ = ( konstante_1, ..., konstante_m );
       name = RECORD
                CASE typ OF
                  konstante_1: ( komponente_11; ...; komponente_1n1 );
                  ...
                  konstante_m: ( komponente_m1; ...; komponente_mnm )
              END;
Auch in diesem Fall steht für alle Varianten ein gemeinsamer Speicherbereich zur Verfügung.

Beispiel (Pascal++):

  TYPE datentyp = (int, byt, ch);
       rec = RECORD
               CASE datentyp OF
                 int : ( i : INTEGER );
                 byt : ( b : ARRAY[1..4] OF BYTE );
                 ch :  ( c : ARRAY[1..4] OF CHAR );
             END;
INTEGER beansprucht in Pascal++ 4 Byte, BYTE und CHAR jeweils 1 Byte.

Zur Ausgabe eines Wertes vom obigen Typ rec wird die folgende Prozedur verwendet:

  PROCEDURE write_rec(r: rec);
  VAR k : INTEGER;
  BEGIN
    WITH r DO BEGIN
      Write(i:12);
      FOR k:=1 TO 4 DO Write(b[k]:5); Write(' ');
      FOR k:=1 TO 4 DO Write(c[k]); Writeln;
    END;
  END;
Ein Test mit Pascal++ ergibt folgende Ergebnisse:
     Wertzuweisungen         Ergebnisse
  r.i           r.c
             1  2  3  4
  ---------------------------------------------------------------------
                             Sparc Workstation unter Solaris
  42                                 42    0    0    0   42 *
  32767                           32767    0    0  127   -1 ˜
  32768                           32768    0    0 -128    0
             *                704675840   42    0 -128    0 *
             a  b  c  d      1633837924   97   98   99  100 abcd
  ++                         1633837925   97   98   99  101 abce
  ---------------------------------------------------------------------
                             PC unter DOS
  42                                 42   42    0    0    0 *
  32767                           32767   -1  127    0    0  
  32768                           32768    0 -128    0    0  Ç
             *                    32810   42 -128    0    0 *Ç
             a  b  c  d      1684234849   97   98   99  100 abcd
  ++                         1684234850   98   98   99  100 bbcd
  ---------------------------------------------------------------------
++ steht für die Erhöhung des Wertes um 1.

Ein Vergleich der auf verschiedenen Rechnerplattformen erzielten Ergebnisse zeigen ein wichtiges Problem:

Bedingt durch die unterschiedliche Byte-Anordnung auf den verschiedenen Rechnern ergeben sich zum Teil unterschiedliche Ergebnisse !
Das obige Beispiel deutet aber auch ein interessantes Einsatzfeld für variante Records an:
Es ist möglich zu erkunden, wie das jeweilige Pascal-System bestimmte Datenstrukturen rechnerintern ablegt.

Es zeigt aber auch die Gefahren: Wird der Wert einer Komponente verändert, die Teil eines varianten Records ist, so wird damit zugleich auch der Wert anderer Komponenten verändert.
Geschieht dies versehentlich, so sind - besonders in großen Programmen - derartige Fehler oft nur schwer zu finden.

Weitere Beispiele zu varianten Records: Byte-Anordnung.


Extended Pascal

Der Varianten-Teil des Records kann einen Zweig enthalten, der dann verwendet wird, wenn der Selektor einen Wert hat, der durch die explizit aufgeführten Varianten nicht abgedeckt wird:

  TYPE name = RECORD
                CASE selektor: typ OF
                  konstante_1: ( komponente_11; ...; komponente_1n1 );
                  ...
                  konstante_m: ( komponente_m1; ...; komponente_mnm );
                  OTHERWISE ( komponente_k1; ...; komponente_kl );
              END;

Ein Record kann sowohl einen varianten als auch einen "normalen" Anteil besitzen:

  TYPE name = RECORD
                komponente;
                ...
                komponente;
                CASE selektor: typ OF
                  konstante: ( komponente; ...; komponente );
                  ...
                  konstante: ( komponente; ...; komponente )
              END;
Beispiel:
  TYPE typ    = (ganz, reell, zeichen);
       fakten = RECORD
                  name: PACKED ARRAY[1..20] OF CHAR;
                  CASE code: typ OF
                    ganz:    (n: INTEGER);
                    reell:   (r: REAL);
                    zeichen: (c: CHAR);
                  END;

Variante Records werden - aus gutem Grund - nicht sehr oft verwendet.
Ihr Einsatz sollte genau überdacht werden, da sie nur bedingt zu besser verständlichen Programmen führen.



P. Böhme, 21.08.1996