Arbeiten mit .NET: Grundlagen: Datentypen/ Ganze Zahlen

In diesem Kapitel erhalten Sie genauere Erläuterungen zu denjenigen einfachen Datentypen, mit denen ganze Zahlen verarbeitet werden.

Überblick

Bearbeiten

Die folgende Tabelle nennt zu jedem Datentyp, der für eine ganze Zahl steht, den Standardwert sowie das mögliche Minimum und Maximum. Als Postfix oder Suffix wird ein Zeichen genannt, das an den Wert angehängt wird, um den Typ zu kennzeichnen. Wie in der Gesamtübersicht sind die vorgeschriebenen Standardtypen (die "CLS-kompatiblen") fett gedruckt.

Klassenname CLS Standard Postfix Minimum Maximum
Byte ja 0 (kein) 0 255
SByte nein 0 (kein) –128 127
Int16 ja 0 (kein) –32768
= –215
32767
= 215–1
Int32 ja 0 (kein) –2.147.483.648
= –231
2.147.483.647
= 231–1
Int64 ja 0 L für C#
L oder & für VB
–9.223.372.036.854.775.808
= –263
9.223.372.036.854.775.807
= 263–1
UInt16 nein 0 (kein) 0 65535
= 216–1
UInt32 nein 0 (kein) 0 4.294.967.295
= 232–1
UInt64 nein 0 (kein) 0 18.446.744.073.709.551.615
= 264–1

Der folgende Code als Teil einer Main-Methode zeigt ein paar dieser Eigenschaften an:

C#-Quelltext
int i1 = 123;
long i2 = -345;
short i3 = 567;
// byte i4 = 890;  
// byte i4 = -1;
// Fehler CS0031: Der Konstantenwert 890 kann nicht in byte konvertiert werden.
var i5 = -789L;
Console.WriteLine("i1 = " + i1.ToString());
Console.WriteLine("i2 = " + i2.ToString());
Console.WriteLine("i3 = " + i3.ToString());
Console.WriteLine("i5 = " + i5.ToString());
Console.WriteLine(int.MinValue);
Console.WriteLine(long.MaxValue);
Console.WriteLine(byte.MinValue);
Console.WriteLine(byte.MaxValue);
Console.ReadKey();
VB.NET-Quelltext
Dim i1 As Integer = 123
Dim i2 As Long = -345
Dim i3 As Short = 567
' Dim i4 As Byte = 890
' Dim i4 As Byte = -1
' Fehler BC30439: Der Konstantenausdruck ist im Typ Byte nicht darstellbar.
Dim i5 = -789L
Console.WriteLine("i1 = " + i1.ToString())
Console.WriteLine("i2 = " + i2.ToString())
Console.WriteLine("i3 = " + i3.ToString())
Console.WriteLine("i5 = " + i5.ToString())
Console.WriteLine(Integer.MinValue)
Console.WriteLine(Long.MaxValue)
Console.WriteLine(Byte.MinValue)
Console.WriteLine(Byte.MaxValue)
Console.ReadKey()

Der Variablen i4 wird ein falscher Wert zugewiesen. Diese Zuweisung ist deshalb als Kommentar ungültig gemacht; die Fehlermeldung wird zitiert. Bemerkenswert ist, dass der C#-Compiler und der VB-Compiler den Fehler unterschiedlich beschreiben.

Hinweise

Bearbeiten

Positiv und negativ: Sowohl die Übersicht als auch die Beispiele zeigen: Byte kann nur positive Werte annehmen, die anderen Standardtypen sowohl positive als auch negative.

Hexadezimale Werte: Bisher haben wir nur die Dezimaldarstellung ganzer Zahlen verwendet. Sie können aber durch ein Präfix auch in Hexadezimaldarstellung (Zahlen zur Basis 16, Kurzfassung: Hex-Form) oder Oktaldarstellung (Zahlen zur Basis 8) angegeben werden.

C#-Quelltext
// Präfix "0x" für Hex-Darstellung - 0 ist die Ziffer
byte i4 = 0x1F;
Console.WriteLine("i4 = " + i4.ToString());
// Oktaldarstellung nicht vorgesehen
VB.NET-Quelltext
' Präfix "&H" für Hex-Darstellung
Dim i4 As Byte = &H1F
Console.WriteLine("i4 = " + i4.ToString())
' Präfix "&O" für Oktaldarstellung - O ist der Buchstabe
Dim i6 As Byte = &O37
Console.WriteLine("i6 = " + i6.ToString())
  Ausgabe
i4 = 31

Für alle diese Datentypen stehen die folgenden Möglichkeiten zur Verfügung:

  • In den Abschnitten zu Datentypen verarbeiten werden behandelt:
    • Vergleiche zwischen Werten desselben Typs
    • Rechenoperationen zwischen Werten desselben Typs
  • In den Abschnitten zu Typumwandlungen werden behandelt:
    • Umwandlung einer Zahl in einen String
    • Umwandlung eines Strings in eine Zahl
    • Umwandlung zwischen Zahlen verschiedener Typen

Mit dem letzten Schritt sind auch Vergleiche und Rechenoperationen zwischen Werte verschiedener Typen möglich.

Überlauf des Wertebereichs

Bearbeiten

  Die folgenden Überlegungen gelten für alle ganzen Zahlen. Wir erklären es für den Datentyp Byte, weil es dabei am leichtesten zu erklären und zu verstehen ist. Für Dezimalzahlen (im nächsten Kapitel) wirkt sich das Problem der Maximal- und Minimalwerte anders aus.

Nehmen wir uns einmal den möglichen Maximalwert und addieren 1.

C#-Quelltext
byte i1 = byte.MaxValue;
i1 = i1 + 1;
Console.WriteLine(i1);
VB.NET-Quelltext
Dim i1 As Byte = Byte.MaxValue
i1 = i1 + 1
Console.WriteLine(i1)
  Ausgabe
System.OverflowException: Die arithmetische Operation hat einen Überlauf verursacht.

Der Compiler hat kein Problem damit, aber beim Programmlauf "knallt es". Auch daran erkennt man, dass .NET genau auf die Datentypen achtet. Die Standardeinstellung dazu heißt: "Auf arithmetischen Über-/Unterlauf überprüfen".

Wir müssen uns als Programmierer deshalb vorher genau überlegen und entscheiden, was wir beim "Überlauf" wollen:

  • Wenn nichts gesagt wird, wird das Programm einfach mit einer Fehlermeldung abgebrochen. Das ist selten sinnvoll, verlangt also vorher eine Reaktion.
  • Mit welcher speziellen Maßnahme soll das Programm in einem solchen Fall reagieren? Das wird in den Kapiteln über Exception (Ausnahmen, Fehlerbehandlung) behandelt.
  • Oder soll das Programm automatisch innerhalb des vorgegebenen Datenbereichs bleiben? Das kann auf verschiedenen Wegen gesteuert werden.
Über/Unterlauf bei C# berücksichtigen

Sie haben folgende Möglichkeiten:

  • Deaktivieren Sie in den Projekt-Eigenschaften die Option "Auf arithmetischen Über-/Unterlauf überprüfen".
  • Deaktivieren Sie diese Option für eine bestimmte Anweisung (oder für einen Block von Anweisungen):
i1 = unchecked((byte)(i1+1));
  • Benutzen Sie zwischendurch einen Datentyp mit größerem Wertebereich und schränken Sie erst das Ergebnis mit der Modulo-Funktion ein:
int i2 = i1 + 1;
i1 = (byte)(i2 % (byte.MaxValue+1));
Über/Unterlauf bei Visual Basic.NET berücksichtigen

Sie haben folgende Möglichkeiten:

  • Deaktivieren Sie in den Projekt-Eigenschaften die Option "Auf arithmetischen Über-/Unterlauf überprüfen".
  • Benutzen Sie zwischendurch einen Datentyp mit größerem Wertebereich und schränken Sie erst das Ergebnis mit der Modulo-Funktion ein:
Dim i2 As Integer = i1 + 1
i1 = CByte(i2 Mod (Byte.MaxValue + 1))

Wir möchten bereits jetzt auf weitere Hinweise in den Kapiteln zu Typumwandlungen aufmerksam machen.

Welchen Typ soll ich nehmen?

Bearbeiten

Diese Frage stellen sich Programmieranfänger und erfahrene Programmierer bei Zahlenwerten immer wieder. Die wichtigste Empfehlung hier ist, sich ein System zu entwickeln und das dann konsequent durchzusetzen.

Für ganze Zahlen ist der Datentyp System.Int32 zu empfehlen:

  • Der Wertebereich dieses Typs ist fast immer groß genug.
  • Auch sehr viele Daten und Methoden des .NET-Frameworks verwenden diesen Typ.
  • Auf den bisherigen "gängigen" PCs mit 32-Bit-Prozessor wird eine Int32-Zahl am schnellsten verarbeitet, weil sie ebenfalls 32 Bit groß ist.
  • Auf neueren PCs mit 64-Bit-Prozessor könnte man aus diesem Grund Int64 empfehlen. Dann würde man sich aber auf diesen Prozessortyp festlegen; deshalb ist zurzeit noch Int32 praktischer.

Manchmal wird dazu geraten, möglichst kleine Variablen zu verwenden, damit die Anwendung wenig Speicher belegt. Das war 1960 sinnvoll, als 1k Byte RAM 3000 Dollar kostete. Spätestens 1990, als 1k Byte RAM nur noch 20 Pfennig kostete, war das nicht mehr sinnvoll.

  • Angenommen, Sie stellen 500 Variablen von Int32 auf Int16 um, wodurch Sie 1000 Byte einsparen. Ihr Arbeitsspeichers ist vermutlich eine Million Mal größer, und der Prozessor-Cache einige tausend Mal.
  • Die CPU liest bei jedem Speicherzugriff immer 64 Bit parallel. Aus einem 64-Bit-Wort kleinere Datentypen zu „vereinzeln“, kostet Rechenzeit. Ein guter Compiler wird deshalb jede Variable in einem separaten 64-Bit-Wort ablegen.
  • Für die Maßstäbe der Anwendungsprogrammierung ist eine solche Erbsenzählerei eher als Fehlerquelle anzusehen. Fehler durch zu klein bemessene Zahlenbereiche sind nur schwer zu lokalisieren.

Allenfalls bei der Programmierung für mobile Geräte wie PDAs kann man abwägen, ob man lieber schneller oder ressourcenschonender arbeiten möchte.

Zusammenfassung

Bearbeiten

Es gibt mehrere ganzzahlige Datentypen, die sich im Wertebereich unterscheiden. Der am meisten verwendete Standardtyp ist System.Int32; er ist auch fast immer zu empfehlen. Wir brauchen uns also nur zu merken:

 

Merke
Der Integer-Datentyp kann irgendwas um ± 2 Milliarden aufnehmen. Das genügt für fast alle Situationen.


Übungen

Bearbeiten

Allgemeiner Hinweis: Mit der Formulierung Standardtyp sind immer die CLS-kompatiblen gemeint. Unter der Formulierung Datentyp sind alle hier behandelten Datentypen zu verstehen.

Übung 1 Datentypen und Wertebereich Zur Lösung

Hinweis: Es sind jeweils mehrere Antworten zulässig.

  1. Welcher Datentyp kann die Zahl 123.456.789 darstellen?
  2. Welcher Datentyp kann die Zahl –9876 darstellen?
  3. Worin unterscheiden sich die Datentypen Byte und Int16? Nicht die Grenzwerte sind gefragt, sondern die Eigenschaften.

Übung 2 Datentypen und Wertebereich Zur Lösung

Welche der folgenden Aussagen sind richtig, welche sind falsch?

  1. Die Standardtypen sind diejenigen, die sowohl positive als auch negative Werte darstellen können.
  2. Int16 steht für 216 Werte, Int32 für 232 Werte, Int64 für 264 Werte.
  3. Der Maximalwert von Int16 beträgt 216.
  4. Der Minimalwert von Int32 beträgt –216.
  5. Der Minimalwert von Int64 beträgt –263.
  6. Der Minimalwert von Byte beträgt 0.

Übung 3 Überlauf des Wertebereichs Zur Lösung

Wenn zwei Int16-Werte miteinander addiert werden, kann der Maximalwert von Int16 überschritten werden. Was kann man tun, damit das Ergebnis ebenfalls ein Int16-Wert ist?

Lösungen

Lösung zu Übung 1 Datentypen und Wertebereich Zur Übung
  1. Int32, Int64; UInt32, UInt64
  2. Int16, Int32, Int64
  3. Byte kann nur positive Werte annehmen, Int16 auch negative. Byte steht für einen 8-Bit-Wert mit maximal 28 Werten, Int16 für einen 16-Bit-Wert mit maximal 216 Werten. Daraus ergeben sich die unterschiedlichen Wertebereiche.

Lösung zu Übung 2 Datentypen und Wertebereich Zur Übung

Die Aussagen 2, 5, 6 sind richtig; die Aussagen 1, 3, 4 sind falsch.

Lösung zu Übung 3 Überlauf des Wertebereichs Zur Übung
  • Beim Compiler kann die Prüfung auf Überlauf/Unterlauf ausgeschaltet werden.
  • Die Zwischenrechnung erfolgt über eine Int32-Variable; das Ergebnis wird mit der Modulo-Funktion in einen Int16-Wert umgerechnet.