namespace cpp {}

C++ lernen, kennen, anwenden

Benutzer-Werkzeuge

Webseiten-Werkzeuge


kennen:typen

Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen angezeigt.


kennen:typen [2020-07-27 10:04] (aktuell) – angelegt - Externe Bearbeitung 127.0.0.1
Zeile 1: Zeile 1:
 +====== Datentypen ======
 +
 +> Das Definieren von allgemein zu gebrauchenden oder auch anwendungsspezifischen Typen ist in der Tat die wichtigste und grundlegendste Aufgabe in C++.
 +>>---  Bjarne Stroustrup: Die C++ Programmiersprache
 +
 +===== Variablen =====
 +==== Deklaration ====
 +Die Deklaration
 +führt einen Namen ein und ordnet ihm einen Typ zu.
 +Ein Bezeichner ist erst nach seiner Deklaration benutzbar 
 +("declare before use", [[#Geltungsbereich]]).
 +Der [[#Typen|Typ]] 
 +bestimmt das Verhalten des Objektes: 
 +welche Speichergröße dem Objekt im Programm zugeordnet wird,
 +wie diese Bitfolge zu interpretieren ist
 +und welche [[.:operator|Operatoren]] auf den Namen anwendbar sind.
 +
 +Durch die Definition 
 +wird dem Objekt ein Speicherplatz (Adresse) zugeordnet.
 +Jedes Objekt muss im Programm genau einmal definiert sein ("one definition rule").
 +Für Variablen ist die Deklaration gleichzeitig auch eine Definition,
 +wenn [[#Spezifizierer]]
 +nichts anderes angeben.
 +
 +Syntax: 
 +>  Spezifizierer Typ DeklariertesObjekt Initialisierer '';''
 +<code cpp>
 +extern int anzahl;
 +double x, y, z;
 +
 +char zeichen = 'j';
 +int const GROESSE = 42;
 +float feld[GROESSE];
 +
 +float* zeiger = &feld[0];
 +float& anfang = feld[0];
 +char* (*zeiger_auf_zeichenkettenfunktion)(char[], char const[]) = std::strcat; 
 +</code>
 +
 +[[#Spezifizierer]] (wie [[.:keywords#extern]] und [[.:keywords#const]])
 +und [[#Anfangswerte|Initialisierer]] zur Zuweisung von Anfangswerten sind optional.
 +Mehrere Objekte können als (kommagetrennte) Liste deklariert werden.
 +Durch [[.:operator|Operatoren]] ''[] * & ()'' 
 +werden [[#zusammengesetzte Datentypen]] ([[#Felder]], [[#Zeiger]] und [[#Referenzen]]) gebildet. 
 +Runde Klammern spielen eine Doppelrolle als Funktionsklammer und zur Vorrangregelung.
 +
 +Kombinationen der Operatoren können beliebig komplex sein.
 +Zum Verständnis sollten die Deklarationen von innen nach außen gelesen werden,
 +d.h. vom neu eingeführten Namen ausgehend entsprechend der 
 +[[.:operator#Rangfolge]] der Operatoren:
 +Der oben definierte Bezeichner ''zeiger_auf_zeichenkettenfunktion''
 +ist ein ''*''Zeiger auf eine Funktion ''(...)'' 
 +mit einem ''char[]''-Feld und einem ''char const[]''-Feld als Parameter
 +und einem ''*''Zeiger auf ''char'' als Ergebnistyp.
 +Der ''zeiger_auf_zeichenkettenfunktion''
 +erhält die Einsprungadresse der Funktion ''strcat''
 +als Anfangswert. Die Typprüfung des Compilers akzeptiert die Zuweisung nur, 
 +weil die Funktion ''strcat'' aus der Bibliothek <[[.:include:cstring]]> als
 +
 +<code cpp>
 +char* strcat(char*, char const*);
 +</code>
 +deklariert ist (Feldparameter werden als Zeiger behandelt); 
 +Funktionsnamen sind Adressen im Maschinencode, also Zeiger auf die Funktion.
 +
 +==== Geltungsbereich und Lebensdauer ====
 +Der Bezeichner ist ab seiner Deklaration bekannt 
 +und darf im folgenden Quelltext benutzt werden.
 +Erfolgte die Deklaration in einem [[.:begriffe#Block]] 
 +aus geschweiften Klammern ''{}'', 
 +ist der Name nur [[.:begriffe#lokal]] bis zum Ende dieses Blockes gültig.
 +Außerhalb von Blöcken deklarierte Bezeichner sind bis zum Ende des Quelltextes 
 +([[.:begriffe#global]]) gültig.
 +
 +Lokale Bezeichner, dazu zählen auch Funktionsparameter, 
 +sind unabhängig von äußeren Bezeichnern definierbar.
 +Die lokalen Bezeichner verdecken in ihren Geltungsbereich 
 +gleichnamige Bezeichner außerhalb des Blockes.
 +
 +Die Lebensdauer und damit der Speicherplatzbedarf globaler Variablen
 +erstreckt sich über die gesamte Programmlaufzeit (statische Variablen).
 +
 +Für lokale Variablen wird beim Eintritt in den Block automatisch Speicher 
 +auf dem Stapel reserviert und beim Verlassen des Blockes wieder freigegeben.
 +Damit geht auch der gespeicherte Wert verloren.
 +
 +==== Spezifizierer ====
 +[[.:begriffe#Speicherklasse|Speicherklassen-Spezifizierer]] 
 +beeinflussen die Lebensdauer bzw. den Speicherort von Variablen.
 +
 +  * Die Angabe [[.:keywords#extern]] macht deutlich, dass der Bezeichner an dieser Stelle nur deklariert und nicht definiert werden soll. Der deklarierte Name ist anderswo global definiert, z.B. in einer anderen Quelltextdatei ([[.:module|Modul]]) des Programms.
 +  * Mit [[.:keywords#register]] wird dem Compiler empfohlen, eine zeitkritische lokale Variable direkt im Prozessorregister zu halten statt sie auf dem Speicher abzulegen. Damit hat diese Variable auch keine Speicheradresse mehr.
 +  * Mit [[.:keywords#static]] gekennzeichnete globale Variablen sind vor dem [[.:keywords#extern]]-Zugriff aus in einer anderen Quelltextdatei geschützt.
 +  * Als [[.:keywords#static]] deklarierte lokale Variablen werden beim Programmstart angelegt und behalten ihren Wert auch nach dem Verlassen der Funktion. Trotz statischer Lebensdauer bleibt ihr Geltungsbereich lokal auf die Funktion begrenzt.
 +
 +<code cpp>
 +int noch_ein_Bier_bitte()
 +{
 +  static int biere = 0;
 +  return ++biere;       // Anzahl der bestellten Biere  
 +}
 +</code>
 +Durch [[.:keywords#const]] läßt sich
 +(unabsichtliches) Ändern des Variablenwertes nach der Initialisierung verbieten.
 +Der direkte Änderungsversuch erzeugt einen Übersetzungsfehler.
 +C-Programmierer sagen zu ''const''-Variablen dennoch ungern Konstante, weil
 +
 +  * sie wissen, wie man ''const'' unterlaufen kann,
 +  * der Drang, das zu tun, beliebig groß werden kann und
 +  * der Begriff [[.:begriffe#Konstante]] vom [[begriffe#Präprozessor]] belegt ist und auch [[.:sprachkern#Literale]] gern als Konstanten bezeichnet werden.
 +
 +Konstante [[#Referenzen]] und konstante [[#Zeiger]]
 +müssen nicht unbedingt auf konstante Objekte verweisen.
 +Sie sind vielmehr eine "freiwillige Selbstverpflichtung",
 +den Wert nicht über diesen Bezeichner zu ändern.
 +
 +Eine als [[.:keywords#volatile]] (flüchtig) markierte Variable
 +muss bei jeder Auswertung neu aus dem Speicher gelesen werden.
 +Optimierungsversuche des Compilers werden unterbunden.
 +Das ist bei Hardwarezugriffen (Ports u.ä.) notwendig, 
 +wenn sich Speicherinhalte "von außerhalb" ändern können:
 +<code cpp>
 +char const volatile far* COM1 = (char far*) 0x3F8; // serial port unter DOS
 +</code>
 +Eine [[.:keywords#mutable]] (veränderbar) gekennzeichnete 
 +[[.:begriffe#Komponente]] eines 
 +[[#zusammengesetzter Datentyp|zusammengesetzten Datentyps]] 
 +darf auch dann geändert werden,
 +wenn die umgebende Struktur oder Klasse logisch konstant ist:
 +
 +<code cpp>
 +struct Count 
 +{
 +  mutable int counter; 
 +};
 +
 +void f(Count const& c)
 +{
 +  c.counter++;
 +}
 +</code>
 +
 +==== Anfangswerte ====
 +Variablen können, Zeiger sollten, 
 +Konstanten und Referenzen müssen bei ihrer Definition Werte erhalten.
 +Neben der [[.:operator#Zuweisung]] mit dem Gleichheitszeichen
 +ist auch die Übergabe von Startwerten in Klammern möglich.
 +Diese aus [[.:begriffe#SmallTalk]]
 +übernommene Schreibweise ist auch für [[begriffe#Konstruktor|Konstruktoren]]
 +zusammengesetzter Typen üblich.
 +<code cpp>
 +int i = 3;     // Variablendefinition in "C-Schreibweise"
 +int j(i);      // Variablendefinition in "SmallTalk-Schreibweise"
 +               // aber:
 +int f(int i);  // Funktionsdeklaration, keine Variablendefinition!
 +</code>
 +Seit C++11 kann die Übergabe von Anfangswerten auch in geschweiften Klammern erfolgen ([[begriffe#uniform initialization]]). Dabei werden Typumwandlungen, die zu Datenverlust führen können (narrowing conversions), als Fehler betrachtet:
 +<code cpp>
 +int k{9};      // ok
 +int l{9.0};    // Fehler: Umwandlung double -> int, möglicher Datenverlust 
 +int m{9.5};    // Fehler: Abrunden zu 9 ist Datenverlust.
 +</code>
 +Der Typ der Variable erschließt sich aus dem Initialisierungswert, wenn als Typ ''auto'' angegeben wird.
 +Bei komplexen Typbezeichnern wie ''std::vector<double>::iterator'' ist das eine Erleichterung.
 +Diese Art der Variablendefinition lässt sich (fast) durchgehend nutzen ([[begriffe#almost always auto]]) --- der Typ kann auch rechts vom Zuweisungsoperator erscheinen.
 +C++17 erlaubt zudem Zugriff eines Bestandteile eines [[#zusammengesetzte Typen|zusammengesetzten Typs]] unter neuen Namen.
 +<code cpp>
 +auto n = 3;                  // int
 +auto p = std::pair{6, true}; // "almost always auto"-Stil 
 +auto  [value, success] = p;  // C++17 structured bindings, Kopie der Werte
 +auto& [v, done] = p;         // Referenz, Schreiben in die Bestandteile von p möglich
 +</code>
 +
 +
 +===== Typen =====
 +C++ ist eine streng typisierte Sprache. Das Typsystem enthält
 +
 +  * vordefinierte fundamentale oder [[#Grundtypen]]
 +    * [[#ganzzahlige Typen]] für Wahrheitswerte, Zeichen und Ganzzahlen,
 +    * [[#Gleitkommatypen]]
 +  * und daraus ableitbarenoder [[#zusammengesetzte Typen]]:
 +    * [[#Felder]],
 +    * [[#Zeiger]],
 +    * [[#Referenzen]],
 +    * [[#Aufzählungen]],
 +    * [[#Klassen]],
 +    * [[#Vereinigungen]].
 +
 +Mit dem Schlüsselwort [[.:keywords#typedef]]
 +sind neue Namen für Typen festlegbar.
 +
 +===== Grundtypen =====
 +==== Ganzzahlige Typen ====
 +<code cpp>
 +bool
 +</code>
 +Der Typ [[.:keywords#bool]] für Wahrheitswerte 
 +und [[.:operator#logische Operationen]] nimmt 
 +einen der beiden möglichen Werte [[.:keywords#true]]
 +und [[.:keywords#false]] an.
 +Der Wert 0 wird als ''false'' betrachtet,
 +jeder andere Wert (egal welchen Typs) wird zu ''true''.
 +Umgekehrt wird bei [[#Typumwandlung]]
 +''true'' zum Wert 1, ''false'' zu 0.
 +
 +<code cpp>
 +char       signed char     unsigned char     wchar_t
 +</code>
 +Zeichen haben den Typ [[.:keywords#char]].
 +Dieser hat meistens 8 bit Breite 
 +und kann damit einen von 256 verschiedenen Werten aufnehmen.
 +Es existieren verschiedene Standards 
 +(EBCDIC, ASCII, ISO 8859-1, ISO 10646, 
 +Unicode, UCS32, ...),
 +den einzelnen Zeichen Zahlenwerte zuzuordnen.
 +Welcher Zeichensatz verwendet wird, 
 +ist maschinen- und betriebssystemabhängig.
 +Für Zeichensätze wie Unicode existiert ein Datentyp 
 +[[.:keywords#wchar_t]].
 +
 +Zeichentypen werden als Ganzzahltypen aufgefasst,
 +weil mit ihnen auch 
 +[[.:operator#arithmetische Operationen]]
 +(mit begrenzten Werteumfang) möglich sind.
 +Ob ein ''char'' vorzeichenbehaftet 
 +([[.:keywords#signed]] -128...127)
 +oder nicht vorzeichenbehaftet ([[.:keywords#unsigned]] 0...255)
 +behandelt wird, ist compilerabhängig.
 +Ist der Unterschied wichtig, 
 +können ''signed char'' und ''unsigned char'' genutzt werden.
 +C++17 definiert in [[.:include:cstddef]] den Datentyp ''std::byte'' über ''unsigned char'' mit eingeschränktem Operationsumfang zur 
 +[[.:operator#bitweise_operatoren|Bitmanipulation]].
 +
 +<code cpp>
 +int        unsigned
 +short      unsigned short     
 +long       unsigned long
 +</code>
 +Der Ganzzahltyp [[.:keywords#int]]
 +nimmt typisch die Verarbeitungsbreite eines Maschinenworts an.
 +Diese kann mit dem [[.:keywords#sizeof]]-Operator
 +ermittelt werden: ''n = 8*sizeof(int);''
 +Der Wertebereich der Ganzzahl
 +umfasst (Zweierkomplementdarstellung vorausgesetzt)
 +die Werte ''-pow(2,n-1)'' bis ''pow(2,n-1)-1''.
 +
 +Die Modifikationen [[.:keywords#short|short int]] und
 +[[.:keywords#long|long int]] können einen kleinere bzw. 
 +größere Breite besitzen.
 +Typisch sind 16 bit und 32 bit bzw. 64 bit.
 +Zu jeder ''int''-Variante (''short'', ''int'', ''long''
 +gibt es eine ''unsigned''-Variante,
 +deren Wertebereich 0 bis ''pow(2,n)-1'' umfasst.
 +
 +In der Bibliothek [[.:include::cstdint]] definierte Typen wie ''uint8_t'', ''int_least16_t'' oder ''int_fast64_t'' kommen zum Einsatz, 
 +wenn exakte oder Mindestwerte für Speicherbedarf oder Wertebereich bzw. Verarbeitungsgeschwindigkeit von Bedeutung sind. 
 +
 +Die Bibliothek <[[.:include:climits|climits]]>
 +definiert Konstanten mit den Grenzen der Wertebereiche.
 +Die Schablone ''numeric_limits<T>''
 +aus <[[.:include:limits|limits]]> 
 +bietet eine einheitliche Schnittstelle für Größeninformationen.
 +
 +==== Gleitkommatypen ====
 +<code cpp>
 +float     double      long double
 +</code>
 +Fließkomma- oder Gleitkommatypen nehmen gebrochene Zahlen
 +mit begrenztem Wertebereich und beschränkter Genauigkeit auf.
 +Typischerweise sind nur 6 führende Ziffern einer 
 +[[.:keywords#float]]-Zahl exakt darstellbar.
 +Doppelt genaue Zahlen ([[.:keywords#double]]) 
 +erlauben einige Stellen mehr,
 +''long double'' (erweitert genaue Zahlen) evtl. noch mehr.
 +Angaben zum Wertebereich und zur möglichen Genauigkeit
 +sind aus den Bibliotheken <[[.:include:cfloat|cfloat]]> und
 +[[.:include:limits|limits]]> entnehmbar.
 +Der Wertebereich der einfach genauen 
 +ist eine Untermenge der doppelt genauen Gleitkommazahlen.
 +
 +Nicht jede gebrochene Zahl ist als endlicher Dualbruch darstellbar.
 +Beim Rechnen mit Gleitkommazahlen kommt es deshalb zu Rundungsfehlern.
 +Die Auslöschung signifikanter Stellen bei der Differenzbildung
 +lässt Genauigkeit verloren gehen.
 +Einige numerische Rechenverfahren reagieren empfindlich
 +auf geringfügige Änderungen von Startwerten (Instabilität oder Chaos).
 +
 +> Die Auswahl der richtigen Genauigkeit für ein Problem, bei dem die Auswahl relevant ist, erfordert ein weitgehendes Verständnis von Gleitkommaberechnungen. Falls Sie dieses Wissen nicht haben, holen Sie sich Hilfe, nehmen Sie sich die Zeit zum Lernen oder benutzen Sie ''double'' und hoffen das beste.
 +>>---  Bjarne Stroustrup: Die C++ Programmiersprache
 +
 +==== Typumwandlung ====
 +Werte der Grundtypen sind trotz strenger Typprüfung 
 +nahezu beliebig ineinander umwandelbar.
 +Führt die Umwandlung zu Genauigkeitsverlust 
 +oder ganz aus dem Wertebereich des Zieltyps hinaus,
 +kann der Compiler Warnungen ausgeben.
 +Der Programmierer sollte diese Warnungen ernst nehmen,
 +da sie zu subtilen Laufzeitproblemen führen können.
 +Typumwandlungen können automatisch (bei Wertzuweisungen,
 +Rückgabe von Funktionswerten und in Rechenoperationen) 
 +oder auch ausdrücklich durch einen 
 +[[.:operator#Typkonverter|Typumwandlungsoperator]] erfolgen.
 +Die ausdrückliche Konversion schaltet die Compiler-Warnung ab.
 +<code cpp>
 +int  i = 65;
 +char c = char(i);
 +// char d{i}; // C++11 Fehler: narrowing
 +</code>
 +Passt der Wert eines Ausdrucks in den Wertebereich des Zieltyps,
 +bleibt der Wert erhalten, auch Vorzeichen werden korrekt behandelt.
 +Bei der Umwandlung von Gleitkommazahlen in Ganzzahlen wird der 
 +gebrochene Anteil abgeschnitten, d.h. zur Null hin abgerundet.
 +Passt der Wert nicht in den Wertebereich eines Zieltyps,
 +werden bei ganzzahligen Typen höherwertige Bits weggelassen 
 +(Moduloarithmetik beim [[.:begriffe#Überlauf]]),
 +bei Gleitkommatypen ist das Ergebnis nicht definiert.
 +Die ab C++11 eingeführte, "uniform initialization" genannte Schreibweise behandelt die Einschränkung des Wertebereichs (narrowing) als Fehler.
 +
 +===== Zusammengesetzte Typen =====
 +==== Felder ====
 +Wird ein Objekt als ''Name[Anzahl]'' deklariert,
 +so handelt es sich um ein Feld mit der Anzahl typgleicher Elemente.
 +Die Anzahl der Elemente (Dimension oder Feldgröße) muss eine ganzzahlige Konstante sein.
 +Die Feldelemente belegen einen zusammenhängenden Speicherbereich.
 +Der Zugriff auf die Feldelemente ''Name[0]'' bis ''Name[Anzahl-1]'' 
 +erfolgt ohne Bereichsprüfung.
 +Schreibzugriffe außerhalb der Feldgrenzen haben schwer lokalisierbare,
 +häufig fatale Folgen.
 +
 +Mehrdimensionale Felder sind Felder von Feldern. 
 +Sie werden durch mehrere aufeinander folgende eckige Klammern beschrieben.
 +Zwischen benachbarten Speicherplätzen ändert sich der rechteste 
 +(innerste) Feldindex am schnellsten ("zeilenweise" Anordnung).
 +
 +Felder können mit Anfangswerten belegt werden:
 +
 +<code cpp>
 +int rechteck[2][3] = { {1, 2, 3}, {4, 5, 6} };
 +</code>
 +Die inneren geschweiften Klammern können bei der Initialisierungsliste weggelassen werden.
 +Auch eine unvollständige Initialisierung ist möglich:
 +
 +<code cpp>
 +int primzahlen[100] = { 2, 3 }; // weitere werden später berechnet
 +int y[2][3] = { 1, 2, 3  };     // nur Zeile  y[0][j] belegt  
 +int z[2][3] = { {1}, {4} };     // nur Spalte z[i][0] belegt
 +</code>
 +Fehlt die äußerste, am weitesten links stehende Felddimension,
 +wird sie vom Compiler aus der Anzahl der Elemente in der Initialisiererliste bestimmt.
 +[[.:funktion#Feldparameter]]
 +benötigen ebenfalls die äußerste Dimensionsangabe nicht, 
 +da Feldparameter als [[#Zeiger]]
 +auf den Feldanfang behandelt werden.
 +Weitere Dimensionen müssen jedoch angegeben sein.
 +
 +==== Zeiger ====
 +Ein Zeiger (engl. pointer) enthält die Adresse eines Objektes im Hauptspeicher.
 +Die Deklaration ''Typ *zeiger'' kann auf zwei Weisen gelesen werden:
 +
 +  - ''zeiger'' ist ein Zeiger auf eine ''Typ''-Variable.
 +  - Der Ausdruck ''*zeiger'' besitzt den ''Typ'' (sozusagen als "Muster" für die Verwendung).
 +Der [[.:operator#einstellige Operatoren|Inhaltsoperator]] ''*'' erlaubt den Zugriff
 +auf den Wert im Hauptspeicher, dessen Adresse im Zeiger hinterlegt ist.
 +
 +Wird ein Zeiger in der Form ''*zeiger'' benutzt, 
 +muss er vorher eine gültige Speicheradresse erhalten haben
 +(z.B. über den [[.:operator#einstellige Operatoren|Adressoperator]] ''&''). 
 +Nicht initialisierte "baumelnde" Zeiger sind eine gefürchtete Fehlerquelle.
 +Nichtgenutzte Zeiger sollten auf ''NULL'' gelegt ("geerdet") werden.
 +Vor dem Zugriff auf den Inhalt kann dann geprüft werden, 
 +ob der Zeiger auf etwas zeigt:
 +
 +<code cpp>
 +  int i;
 +  int *ip = &i; // Zeiger ip erhält Adresse von i (ip zeigt auf i)
 +
 +  if (ip)       // ip sollte gültig sein, 
 +  {
 +    *ip = 10;   // ehe über ip der Wert von i angesprochen wird
 +  }
 +  ip = NULL;    // ip wird nicht mehr genutzt
 +</code>
 +
 +==== Referenzen ====
 +Referenzvariablen ''Typ& aliasname = variable'' definieren feste Aliasnamen,
 +die für ihre Lebensdauer fest 
 +mit der Speicheradresse einer anderen Variable verbunden sind.
 +Referenzvariablen werden relativ selten "solo" verwendet,
 +um mehrfache umständliche Ausdrücke zu vermeiden.
 +
 +<code cpp>
 +int matrix[3][3];
 +int &mitte = matrix[1][1];
 +mitte = 15;                // statt matrix[1][1] = 15;
 +</code>
 +Häufiger werden sie als 
 +[[.:funktion#Referenzparameter]] eingesetzt.
 +
 +[[begriffe#rvalue-Referenz|Weiterleitende Referenzen]] (ab C++11) ''Typ&& aliasname = ausdruck'' können sowohl Referenzen auf "Linkswerte" ([[begriffe#lvalue]]) als auch auf "Rechtswerte" ([[begriffe#rvalue]]) übernehmen. Bei Linkswerten kollabiert die universelle Referenz zu ''Typ&'', bei Rechtswerten wird der Wert durch Verschieben ([[begriffe#Verschiebesemantik]]) oder wenn das nicht möglich ist, durch Kopieren für den Sichtbarkeitsbereich des Aliasnamens am Leben erhalten. 
 +==== Aufzählungen ====
 +Aufzählungen (engl. enumerations) 
 +sind Sammlungen benannter ganzzahliger (int-)Konstanten,
 +denen ein gemeinsamer Typname zugeordnet werden kann.
 +Die Konstanten werden mit 0 beginnend aufsteigend nummeriert,
 +falls ihnen kein anderer Wert zugeordnet wird.
 +
 +Werte vom Aufzählungstyp lassen sich problemlos einer ''int''-Variable zuweisen,
 +umgekehrt jedoch nicht (explizite Typumwandlung erforderlich).
 +
 +Syntax:
 +>  ''enum'' Typname ''{'' Konstantenliste ''}'' Variablenliste'';''
 +<code cpp>
 +enum Woche { SO, MO, DI, MI, DO, FR, SA };
 +enum Muenzen { PFENNIG=1, FUENFER=5, GROSCHEN=10, FUFFZIGER=50 };
 +</code>
 +Typsichere Aufzählungen erlauben keine implizite Umwandlung in Ganzzahlen:
 +<code cpp>
 +enum class TriState : char { unknown, no, yes };
 +TriState s = TriState::unknown;
 +// char c = s;    // nicht erlaubt
 +char c = char(s); // ok
 +</code>
 +Die Angabe eines Grundwertebereichs ist möglich. (Das ist keine [[klassen#Vererbung]]!)
 +==== Klassen und Strukturen ====
 +Vorwärtsdeklarationen können benutzt werden, 
 +solange der Compiler keine Information über den Strukturinhalt benötigt,
 +z.B. um einen Zeiger oder eine Referenz zu deklarieren
 +(unvollständige Typdefinition).
 +
 +Syntax:
 +>  ''struct'' Typname '';''
 +
 +Inhaltlich zusammengehörende Daten auch verschiedener Typen
 +([[.:klassen#Attribut|Attribute]], engl. member data) 
 +und zugehörige Funktionen
 +([[.:klassen#Methode|Methoden]], engl. member functions) 
 +lassen sich als Komponenten einer 
 +Struktur (Schlüsselwort [[.:keywords#struct]]) 
 +oder Klasse (Schlüsselwort [[.:keywords#class]])
 +zusammenfassen,
 +siehe auch [[.:klassen|Klassenkonzept]].
 +
 +Die Instanzen werden bei Zuweisung, 
 +Parameterübergabe und Funktionsrückgabe als Einheit behandelt,
 +d.h. Byte für Byte kopiert.
 +
 +Syntax:
 +>  ''struct'' Typname 
 +>  ''{'' 
 +>>  Zugriffsspezifikation'':''
 +>>  Komponentendeklarationen
 +>  ''}'' Variablenliste '';''
 +
 +Der Zugriff auf die Bestandteile einer Instanz 
 +erfolgt als ''variable.komponente'' oder ''zeiger->komponente''.
 +[[.:klassen#Zugriffsrechte|Zugriffsspezifikationen]]
 +legen fest, von wo aus der Zugriff auf die folgenden Komponenten erlaubt ist.
 +Ohne Zugriffsspezifikation,
 +sind die Komponenten einer Struktur öffentlich
 +([[.:keywords#public]]),
 +die einer Klasse nur den Methoden der Klasse zugänglich
 +([[.:keywords#private]]).
 +Abgesehen davon sind ''struct'' und ''class'' gleichwertig.
 +
 +Besitzt die Struktur keine selbstdefinierten 
 +[[.:klassen#Konstruktoren]],
 +können die Variablen Anfangswerte durch eine Initialisiererliste in geschweiften Klammern erhalten.
 +
 +<code cpp>
 +struct Atom
 +{
 +  char symbol[3];
 +  float masse;
 +};
 +
 +Atom const wasserstoff = { "H", 1.0079 };
 +Atom atom1, atom2;
 +atom2 = atom1 = wasserstoff;
 +
 +float masse = atom1.masse + atom2.masse;
 +</code>
 +
 +==== Vereinigungen und Bitfelder ====
 +Vereinigungen (Schlüsselwort [[.:keywords#union]])
 +überlagern einem Speicherbereich mehrere Bezeichner. 
 +Das Konzept entspricht den varianten Records 
 +in [[.:begriffe#PASCAL]] 
 +oder ''EQUIVALENCE''-Bereichen in [[.:begriffe#FORTRAN]].
 +Je nach Typ der Komponente werden die gleichen Bits unterschiedlich interpretiert.
 +Der Speicherbedarf der Vereinigung entspricht dem größten enthaltenen Typ.
 +Die Nutzung zur Typkonversion ist gefährlich, weil nicht portabel.
 +
 +Syntax:
 +>  ''union'' Typname
 +>  ''{'' 
 +>>  Komponentendeklarationen
 +>  ''}'' Variablenliste '';''
 +
 +Mit Bitfeldern können kleine Informationseinheiten in ein Maschinenwort gepackt werden.
 +Hinter jeder Komponente wird die Anzahl der zu reservierenden Bits angegeben. 
 +Die Bitfeldkomponenten verhalten sich wie kleine Ganzzahlen mit oder ohne Vorzeichen.
 +Für Zwischenräume können unbenannte Bitfeldkomponenten eingeschoben werden.
 +Fast alles an Bitfeldern ist implementierungsabhängig ([[.:beispiel:ieee]]).
 +
 +<code cpp>
 +struct IEEE754Single
 +{
 +  unsigned mantisse : 23;
 +  unsigned exponent : 8;
 +  unsigned sign     : 1;
 +} bits;
 +</code>
  
kennen/typen.txt · Zuletzt geändert: 2020-07-27 10:04 von 127.0.0.1

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki