Berechnungen mit ganzzahligen numerischen Datentypen in Visual Basic .NET und C#
Einleitung
Vielfach wird bei Vergleichen der Programmiersprachen Visual Basic .NET und C# auf das Fehlen von Operatoren für die nicht CLS-konformen vorzeichenlosen ganzzahligen Datentypen in Visual Basic .NET hingewiesen und dies als Argument gegen den Einsatz von Visual Basic .NET gewertet. Weitaus seltener findet in derartigen Gegenüberstellungen Erwähnung, daß in C# Rechenoperationen für die Datentypen UInt8
, UInt16
, Int8
und Int16
immer mit dem Datentyp Int32
durchführt und deshalb zusätzliche Typumwandlungen erforderlich werden. Ziel dieses Artikels ist es, die Gründe für dieses Verhalten von C# zu beschreiben und den Umgang von Visual Basic .NET mit den genannten Datentypen zu untersuchen. Des Weiteren erfolgt eine Bewertung der Unterstützung von Berechnungen mit ganzzahligen numerischen Datentypen in den beiden Programmiersprachen.
Die folgenden Ausführungen beziehen sich auf die Programmiersprachen Visual Basic .NET 7.1 mit Option Strict On
und C# 1.1, beide mit aktivierter Überprüfung auf Ganzzahlüberlauf, sowie das .NET Framework 1.1. Um den Text verständlich zu halten, werden anstelle der sprachspezifischen Typpseudonyme die allgemein bekannten Namen der Typen aus dem .NET Framework verwendet. Die nachstehende Tabelle bietet einen Übersicht über die Namen der Typen im .NET Framework und den Programmiersprachen Visual Basic .NET und C#.
.NET Framework | Visual Basic .NET | C# |
---|---|---|
UInt8 |
Byte |
byte |
UInt16 |
— | ushort |
Int16 |
Short |
short |
UInt32 |
— | uint |
Int32 |
Integer |
int |
UInt64 |
— | ulong |
Int64 |
Long |
long |
Operationen auf ganzzahlige numerische Datentypen in .NET
In MSIL sind die Anweisungen add
, div
, mul
, rem
und sub
zur Durchführung binärer Operationen auf Ganzzahlen für die Typen Int32
und Int64
([1], Teil III CIL Instruction Set, Kap. 1.5 Operand Type Table, Tab. 2 Binary Numeric Operations, S. 10), nicht aber für UInt8
, UInt16
und Int16
definiert. Die Entscheidung dafür mag damit begründet werden, daß in der Praxis mit aktuellen Prozessoren und aufgrund der Wertebereiche der Datentypen die meisten Berechnungen mit den Datentypen der Bitbreiten 32 und 64 durchgeführt werden und Berechnungen mit Datentypen geringerer Bitbreite eher eine Seltenheit darstellen. Zudem können Berechnungen für Datentypen geringerer Bitbreiten problemlos mit den Anweisungen für 32- bzw. 64-Bit-Datentypen simuliert werden. Dazu werden die Operanden beispielsweise in den Datentyp Int32
konvertiert, anschließend mit den dafür definierten Anweisungen die Berechnungen durchgeführt und das Ergebnis in den Zieldatentyp umgewandelt.
Bei Berechnung der Summe zweier Zahlen des Typs Int16
und Zuweisen des Ergebnisses an eine Variable dieses Typs kann selbst dann kein Genauigkeitsverlust auftreten, wenn die Berechnungen unter Verwendung des Datentyps Int32
durchgeführt werden. Möglich ist jedoch, daß beim Umwandeln des Ergebnisses in den Zieldatentyp ein Überlauf eintritt, falls der Wertebereich des Zieldatentyps kleiner ist als jener des Datentyps, mit dem die Berechnung durchgeführt wurde, oder nicht vollständig mit diesem übereinstimmt. Ein Überlauf in Folge von Berechnungen kann selbst dann auftreten, wenn Zielvariable und Berechnung den selben Datentyp besitzen.
Ganzzahlige Berechnungen in Visual Basic .NET
In Visual Basic .NET werden arithmetische Operatoren für die ganzzahligen numerischen Datentypen UInt8
, Int16
, Int32
und Int64
unterstützt (vgl. [2], Kap. 11.13.3 Addition Operator). Bei Datentypen wie UInt8
und Int16
, für die in der CIL keine entsprechenden Anweisungen enthalten sind, werden die Berechnungen mit den Anweisungen für den Datentyp Int32
unter Wahrung der Typsicherheit auf Ebene des Quellcodes simuliert. Die Addition von a
und b
erfolgt mittels der Anweisung add
, welche die beiden Zahlen als Int32
behandelt und keine Überlaufüberprüfung vorsieht. Eine Überprüfung auf einen Überlauf ist nicht erforderlich, da das Ergebnis einer Addition zweier Zahlen des Typs Int16
immer im Datentyp Int32
dargestellt werden kann. Anschließend wird das Ergebnis der Addition mit conv.ovf.i2
in den Datentyp Int16
umgewandelt. Tritt bei der Umwandlung ein Überlauf auf, wird eine Ausnahme des Typs System.OverflowException
geworfen.
Hierbei ist bemerkenswert, daß die Umwandlung in den Typ Int16
unabhängig vom Typ der Variablen, welcher das Berechnungsergebnis zugewiesen wird, erfolgt. Hätte die Zielvariable den Datentyp UInt8
, würde der Compiler zwei aufeinanderfolgende Anweisungen zur Typumwandlungen emittieren; eine conv.ovf.i2
-Anweisung zum Zweck der Umwandlung des Berechnungsergebnisses in den Datentyp Int16
und eine conv.ovf.u1
-Anweisung, die dazu dient, den Wert in den Datentyp der Zielvariablen umzuwandeln. Bei fehlender Optimierung seitens des Compilers könnten daher in unserem Beispiel zwei direkt aufeinanderfolgende conv.ovf.i2
-Anweisungen emittiert werden, von denen eine redundant wäre.
Mit strenger Semantik erlaubt Visual Basic .NET nur erweiternde, nicht jedoch reduzierende implizite Typumwandlungen ([2], Kap. 8.1 Implicit and Explicit Conversions und Kap. 6.2.2 Option Strict
Statement). Bei der Addition zweier Zahlen besitzt, vereinfacht ausgedrückt, das Ergebnis den Typ jenes der beiden Operanden, der einen größeren Wertebereich aufweist. Operanden anderer Typen werden implizit in diesen Typ umgewandelt, sofern es sich dabei um eine erweiternde Umwandlung handelt, andernfalls wäre eine explizite reduzierende Umwandlung erforderlich.
Ganzzahlige Berechnungen in C#
C# stellt keine arithmetischen Operatoren für die Datentypen UInt8
, UInt16
und Int16
bereit (vgl. [3], Kap. 7.7.4 Addition operator) und implementiert damit Operationen lediglich für die in der CIL unterstützten Datentypen, d. h. jene Typen, für die in der MSIL entsprechende Anweisungen bereitstehen. Der im folgenden Listing angegebene Code, in dem die Werte der zwei Variablen a
und b
addiert und die berechnete Summe der Variablen c
zugewiesen werden soll, führt zum Kompilierungsfehler CS0029 (Implizite Konvertierung des Typs int
zu short
nicht möglich). Um den Code kompilierbar zu machen, muß das Ergebnis der Berechnung a + b
explizit in den Typ der Zielvariablen umgewandelt werden (c = (Int16)(a + b)
). Zur Durchführung der Addition wird die IL-Anweisung add.ovf
verwendet, die bei Auftreten eines Überlaufs eine Ausnahme des Typs System.OverflowException
wirft. Die Typumwandlung des Additionsergebnisses erfolgt mittels der Anweisung conv.ovf.i2
, von der ebenfalls im Falle eines Überlaufs eine System.OverflowException
geworfen wird.
Mit der zusätzlichen expliziten Typumwandlung vor Zuweisen des Ergebnisses der Berechnung ähnelt das Verhalten jenem von Visual Basic .NET. Allerdings wird der Codierungsaufwand erhöht, ohne zur Kompilierungszeit oder Laufzeit einen Nutzen zu bringen. Da der Typ der Variablen, die das Berechnungsergebnis aufnehmen soll, zur Kompilierungszeit bekannt ist, kann die Typumwandlung in den Typ des Zuweisungsziels automatisch generiert werden. Eine Erhöhung der Qualität des Quellcodes durch das Erzwingen einer expliziten Typumwandlung kann gleichfalls nicht konstatiert werden, da eine derartige Vorgangsweise bei den Typen Int32
und Int64
auch nicht verpflichtend ist.
Schlußwort
Die Programmiersprachen Visual Basic .NET und C# unterscheiden sich in ihrer Unterstützung für die Durchführung mathematischer Operationen auf Werte ganzzahliger numerischer Datentypen. Ideal wäre eine vollständige typsichere Unterstützung der Operatoren für alle ganzzahligen numerischen Datentypen in Visual Basic .NET und C#. Visual Basic .NET 8.0 erweitert die Programmiersprache um Operatoren für die bisher noch nicht unterstützten vorzeichenlosen numerischen Datentypen. Andererseits ist in C# 2.0 keine mit jener von Visual Basic .NET vergleichbare typsichere Unterstützung von Berechnungen bislang fehlender numerischer Datentypen vorgesehen, weshalb Visual Basic .NET seine Vorzüge gegenüber C#, insbesondere in Interop-Szenarien, weiter ausbauen kann.
Literaturverzeichnis
- [1]
- Microsoft Corporation: Standard ECMA-335 – Common Language Infrastructure (CLI), 2nd edition, ECMA, Dezember 2002.
- [2]
- Microsoft Corporation: Visual Basic Language Specification, Dokumentation zu Visual Basic .NET 2003, MSDN, 2003.
- [3]
- Microsoft Corporation: Standard ECMA-334 – C# Language Specification, 2nd edition, ECMA, Dezember 2002.
Weiterführende Informationen
- Dave Doknjas: Convert Between VB.NET and C#
Unterschiede zwischen Visual Basic .NET und C# hinsichtlich ihrer Typsicherheit.