C # -Byte-Additionsoperation

7

Könnte mir jemand zeigen, warum hier:

%Vor%

Ich muss explizite Typkonvertierung verwenden. Aber hier

%Vor%

Ich muss das nicht tun?

Generiert der Compiler für diese beiden Fälle einen anderen IL-Code? Und welcher Fall ist besser?

    
rpeshkov 26.02.2012, 22:09
quelle

4 Antworten

14

Weil der Standard es erlaubt (siehe den zweiten Fall unten):

  

14.14.2 Zusammengesetzte Zuweisung

     

Eine Operation der Form x op = y wird verarbeitet, indem die binäre Operator-Überladungsauflösung (§14.2.4) so ​​angewendet wird, als wäre die Operation x op y . Dann,

     
  • Wenn der Rückgabetyp des ausgewählten Operators implizit in den Typ x konvertiert werden kann, wird die Operation als x = x op y ausgewertet, mit Ausnahme von x wird nur einmal ausgewertet.

  •   
  • Wenn der ausgewählte Operator ein vordefinierter Operator ist, wenn der Rückgabetyp des ausgewählten Operators explizit in den Typ x konvertiert werden kann und y implizit in den Typ% co_de konvertiert werden kann % oder der Operator ist ein Schichtoperator, dann wird die Operation als x op x = (T)(x ausgewertet, wobei y) der Typ von T ist, außer dass x nur ausgewertet wird einmal.

  •   
  • Andernfalls ist die Verbundzuweisung ungültig und es tritt ein Fehler bei der Kompilierung auf.
  •   

Der IL-Code sollte in diesem Fall im Wesentlichen identisch sein. Wenn die Auswertung von x Nebenwirkungen hat, wird sie natürlich zweimal im Fall b und nur einmal bei Verwendung der Verbundzuweisung ausgewertet.

    
Mehrdad Afshari 26.02.2012, 22:16
quelle
5

Dies ist eine FAQ im C # -Tag, die schwer zu finden ist. Die Notwendigkeit der Besetzung ist zuerst relevant. Der Grund dafür ist, dass die CLI nur eine begrenzte Anzahl gültiger Typen für den Befehl Opcodes.Add IL angibt. Es werden nur Operanden vom Typ Int32, Int64, Single, Double und IntPtr unterstützt. IntPtr ist auch etwas Besonderes, die C # -Sprache verbietet es, dieses zu verwenden.

Daher muss der C # -Compiler eine implizite Konvertierung verwenden, um das Byte auf einen Typ zu heben, den der Operator unterstützt. Es wird Int32 als den nächsten kompatiblen Typ auswählen. Das Ergebnis der Addition ist Int32. Das passt nicht zurück in ein Byte, ohne das Ergebnis zu kürzen, und wirft die zusätzlichen Bits weg. Ein offensichtliches Beispiel ist 255 + 1, das Ergebnis ist 256 in Int32, passt aber nicht zu einem Byte und ergibt 0, wenn es gespeichert wird.

Das ist ein Problem. Die Sprachentwickler haben diese Kürzung nicht mögen, ohne dass Sie explizit die Konsequenzen erkannt haben. Eine Umwandlung ist erforderlich, um den Compiler davon zu überzeugen, dass Sie sich dessen bewusst sind. Ein bisschen wie ein Cop-out, natürlich tendierst du dazu, die Besetzung mechanisch zu produzieren, ohne viel über die Konsequenzen nachzudenken. Aber das macht es zu deinem Problem, nicht von Microsoft:)

Das reiben war der + = Operator, ein sehr netter Operator, um den Condense-Code zu schreiben. Ähnelt der Kürze des Schlüsselworts var . Rock und ein harter Ort, wo legst du die Besetzung hin? Es funktioniert einfach nicht, also haben sie das Problem überstanden und das Abschneiden ohne einen Cast erlaubt.

Bemerkenswert ist, wie VB.NET funktioniert, es ist kein Cast erforderlich. Aber es gibt eine Garantie, dass C # nicht standardmäßig zur Verfügung stellt, wird es eine OverflowException generieren, wenn das Ergebnis nicht passt. Ziemlich nett, aber dieser Scheck kommt nicht umsonst.

Saubere Sprachen zu entwerfen ist ein sehr schwieriges Problem. Das C # -Team hat ausgezeichnete Arbeit geleistet, Warzen nicht. Sonst die Art von Warzen durch Prozessor-Design verursacht. IL hat diese Typenbeschränkungen, weil das auch echte 32-Bit-Prozessoren haben, insbesondere die RISC-Designs, die in den 90er Jahren populär waren. Ihre internen Register können nur 32-Bit-Integer und IEEE-754 Fließkommawerte verarbeiten. Und erlauben nur kleinere Arten in Ladungen und Lagern. Der Intel x86-Core ist sehr beliebt und erlaubt eigentlich grundlegende Operationen auf kleineren Typen. Aber das ist meistens ein historischer Unfall, weil Intel das Design durch die 8-Bit-8080- und 16-Bit-8086-Generationen kompatibel hält. Es ist nicht kostenlos, 16-Bit-Operationen kosten einen zusätzlichen CPU-Zyklus. Zu vermeiden.

    
Hans Passant 26.02.2012 22:29
quelle
0

Die Spezifikation nennt dies als einen speziellen Fall des zusammengesetzten Zuweisungsoperators:

Ссылка

Genauer gesagt, Punkt 2:

  • Andernfalls, wenn der ausgewählte Operator ein vordefinierter Operator ist, wenn der Der Rückgabetyp des ausgewählten Operators kann explizit in den Typ von x, und wenn y implizit in den Typ von x konvertierbar ist, dann Die Operation wird als x = (T) (x opy) bewertet, wobei T der Typ von ist x, außer dass x nur einmal ausgewertet wird.
  

Die zweite obige Regel erlaubt es, x op = y als x = (T) (x op   y) in bestimmten Kontexten. Die Regel existiert so, dass das vordefinierte   Operatoren können als zusammengesetzte Operatoren verwendet werden, wenn der linke Operand ist   vom Typ sbyte, byte, short, ushort oder char. Auch wenn beide Argumente   Sind einer dieser Typen vorhanden, erzeugen die vordefinierten Operatoren ein Ergebnis   vom Typ int, wie in Abschnitt 7.2.6.2 beschrieben. So, ohne es zu werfen   Es wäre nicht möglich, das Ergebnis dem linken Operanden zuzuordnen.

    
Joe 26.02.2012 22:18
quelle
0

Dies aufgrund der impliziten Konvertierungsregeln.

Wenn Sie einen binären Operator + haben, wird das Ergebnis in den größeren der beiden Typen konvertiert. Das Literal 200 ist vom Typ int und daher ist der Typ des Ausdrucks b+200 int. Der Zuweisungsoperator = führt keine implizite Konvertierung durch, sondern einen Fehler. Wie in

%Vor%

Im zweiten Fall erwartet der Operator += das Byte, also wird 200 (das vom Typ int ist, aber in Byte passt) implizit in Byte konvertiert, weil der Compiler es weiß. Folgendes wird nicht kompiliert, da die Kompilierung nicht weiß, ob x in ein Byte passt oder nicht.

%Vor%

Wenn Sie x zu const machen, kompiliert es:

%Vor%     
Petar Ivanov 26.02.2012 22:15
quelle

Tags und Links