2010-04-28 4 views
26

Warum wird die eine Kompilierung Fehler aus folgenden: int ‚auf‚byte‘‚kann nicht implizit Typ umwandeln‘:C# XOR auf zwei Byte-Variablen kompiliert nicht ohne Guss

 byte a = 25; 
     byte b = 60; 

     byte c = a^b; 

Dieser Sinn machen würde, wenn Ich benutzte einen arithmetischen Operator, weil das Ergebnis von a + b größer sein könnte, als in einem einzelnen Byte gespeichert werden kann.

Die Anwendung auf den XOR-Operator ist jedoch sinnlos. XOR hier eine bitweise Operation, die niemals ein Byte überlaufen kann.

ein gegossenes um beide Operanden unter Verwendung funktioniert:

byte c = (byte)(a^b); 
+0

in der Tat ist es seltsam, bitweise Operationen (gut, außer für die Verschiebung nach links) nicht überläuft – Hao

+0

Byte-Operationen im Allgemeinen können Werte größer als 255, wie wenn Sie Schicht verlassen ein Byte, natürlich und/oder Operatoren nicht Ergebnisse größer als Byte erzeugen, aber aus Kompatibilitätsgründen wird das Ergebnis int! –

Antwort

22

Ich kann Ihnen die Logik nicht geben, aber ich kann sagen, warum der Compiler dieses Verhalten vom Standpunkt der Regeln hat, denen der Compiler folgen muss (was vielleicht nicht wirklich das ist, was Sie interessant zu wissen sind).

Von einer alten Kopie der C# spec (ich wahrscheinlich eine neuere Version herunterladen soll), Hervorhebung hinzugefügt:

14.2.6.2 Binary numeric promotions This clause is informative.

Binary numeric promotion occurs for the operands of the predefined + , ? , * , / , % , & , | , ^ , == , != , > , < , >= , and <= binary operators. Binary numeric promotion implicitly converts both operands to a common type which, in case of the non-relational operators, also becomes the result type of the operation. Binary numeric promotion consists of applying the following rules, in the order they appear here:

  • If either operand is of type decimal, the other operand is converted to type decimal, or a compile-time error occurs if the other operand is of type float or double.
  • Otherwise, if either operand is of type double, the other operand is converted to type double.
  • Otherwise, if either operand is of type float, the other operand is converted to type float.
  • Otherwise, if either operand is of type ulong, the other operand is converted to type ulong, or a compile-time error occurs if the other operand is of type sbyte, short, int, or long.
  • Otherwise, if either operand is of type long, the other operand is converted to type long.
  • Otherwise, if either operand is of type uint and the other operand is of type sbyte, short, or int, both operands are converted to type long.
  • Otherwise, if either operand is of type uint, the other operand is converted to type uint.
  • Otherwise, both operands are converted to type int.

Also, im Grunde Operanden kleiner als ein int wird int für diese Operatoren umgewandelt werden (und das Ergebnis wird ein int für die nicht-relationalen Ops sein).

Ich sagte, dass ich Ihnen keine Begründung geben konnte; Ich rate jedoch zu einer - ich denke, dass die Entwickler von C# sicherstellen wollten, dass Operationen, die Informationen verlieren könnten, wenn sie eingeengt würden, diese Engstellenoperation explizit durch den Programmierer in Form einer Besetzung hätten machen müssen. Zum Beispiel:

byte a = 200; 
byte b = 100; 

byte c = a + b; // value would be truncated 

Während diese Art von Abschneiden nicht passieren würde, wenn eine XOR-Operation zwischen zwei Byteoperanden durchgeführt wird, denke ich, dass die Sprachdesigner wahrscheinlich nicht einen komplexeren Satz von Regeln haben wollten, wo einig Operationen würden explizite Umwandlungen erfordern und andere nicht.


Nur eine kleine Anmerkung: die oben genannte Zitat ‚Informations‘ nicht ‚normative‘ ist, aber es deckt alle Fälle in einer einfachen Form zu lesen. Streng (im normativen Sinne) gesprochen, der Grund der ^ Operator verhält sich diese Art und Weise ist, weil die nächste Überlastung für den Bediener, wenn sie mit byte Operanden zu tun ist (von 14.10.1 „Integer logischen Operatoren“):

int operator ^(int x, int y); 

Wie der informative Text erklärt, werden daher die Operanden zu int befördert und ein int Ergebnis wird erzeugt.

+0

+1, Schöne Antwort, sagte Raymond Chen ziemlich genau das gleiche, Microsoft glaube Konsistenz zwischen den Typen ist wichtig für die Benutzerfreundlichkeit. – Ash

+0

Es ist eine würdige Schätzung, aber wenn das das Motiv wäre, wäre es nicht genug durchdacht worden. Selbst im Fall von "int" -Operationen ist der Datenverlust aufgrund eines Integer-Überlaufs immer noch vorhanden. Die Einschränkung byteweiser Operationen hilft in dieser Hinsicht NICHTS. – Assimilater

+0

Gleiches geschieht für 'ushort' mit' ushort aa = 1; ushort bb = 1; ushortcc = aa - bb; 'kann nicht kompiliert werden. –

1

Ich schätze sein, weil der Operator XOR für booleans und ganze Zahlen definiert.

Und eine Umwandlung des Ergebnisses aus dem Integer-Ergebnis in ein Byte ist eine Information-verlierende Umwandlung; benötigt daher eine explizite Besetzung (Nicken vom Programmierer).

0

Dies hat mehr mit den Regeln für das implizite und explizite Casting in der CLI-Spezifikation zu tun. Eine Ganzzahl (int = System.Int32 = 4 Bytes) ist breiter als ein Byte (1 Byte, offensichtlich!). Daher ist jede Umwandlung von int in Byte möglicherweise eine einschränkende Umwandlung. Daher möchte der Compiler, dass Sie dies explizit machen.

+1

Ich denke, die Überraschung hier für das Poster ist, dass das Ergebnis kein weiteres Byte ist. –

2

Der Halbgott Programmierer von Microsoft hat eine Antwort: http://blogs.msdn.com/oldnewthing/archive/2004/03/10/87247.aspx

Und vielleicht ist es mehr über Compiler Design. Sie machen den Compiler einfacher, indem sie den Kompilierprozeß verallgemeinern, müssen nicht den Operanden der Operanden betrachten, also haben sie bitweise Operationen in die gleiche Kategorie wie arithmetische Operatoren eingeordnet. Dadurch, dass ich der Typverbreiterung unterzogen wurde

+1

Ich habe das gerade gelesen. Er redete tatsächlich über Rechenoperatoren nicht bitweise. Er stimmt in den Kommentaren zu, dass dieser Punkt nicht für bitweise Operatoren gilt. – Ash

+0

@Ash: nett für ihn zu fragen. vielleicht sollte Anders den Compiler anpassen und ihn intelligenter machen, und afaict C hat dieses Verhalten nicht –

+0

Das liegt daran, dass C im Allgemeinen kein explizites Casting zwischen verschiedenen Größen von Ganzzahlen erfordert. – dan04

0

Ich dachte, ich erinnerte mich an eine populäre Frage dazu.

byte + byte = int... why?

+0

Es ist nicht ganz dasselbe. Das Hinzufügen von zwei Bytes kann überlaufen. XORing zwei Bytes kann nicht. – dan04

0

Es scheint, weil in C# -Sprache Spezifikationen zu sein, ist es für integer und lange http://msdn.microsoft.com/en-us/library/aa691307%28v=VS.71%29.aspx

So definiert ist, was tatsächlich passiert ist, dass Compiler Byteoperanden wirft implizit in int, weil es keine Datenverlust auf diese Weise. Aber das Ergebnis (das int ist) kann nicht ohne Verlust von Daten (implizit) down-Cast-sein. Also müssen Sie dem Compiler explizit sagen, dass Sie wissen, was Sie tun!

+0

Was in dem im verknüpften Artikel erwähnten Szenario hilfreich wäre, wäre, dass der Compiler den Operator überladen basierend auf dem Rückgabewert täuscht, oder aber "~ b" einen Wert liefert, der kein Integertyp ist, aber in einen konvertiert werden kann angemessen groß wie benötigt. Ein solcher Ansatz könnte in Fällen wie 'longVal & = ~ intVal;' helfen, wo das Ergebnis von '~' wirklich ein 'long' sein sollte. – supercat

0

Warum müssen die beiden Bytes in Ints umgewandelt werden, um das XOR zu tun?

Wenn Sie genauer hinschauen möchten, beschreibt 12.1.2 der CLI-Spezifikation (Partition I), dass auf dem Auswertungsstapel nur int oder long existieren können. Alle kürzeren Integraltypen müssen während der Auswertung erweitert werden.

Leider kann ich keinen passenden Link direkt zur CLI-Spezifikation finden - ich habe eine lokale Kopie als PDF, kann mich aber nicht erinnern, woher ich sie bekommen habe.

-1

FWIW Byte a = 25; Byte b = 60; a = a^b; funktioniert nicht. Jedoch Byte a = 25; Byte b = 60; a^= b; funktioniert.

Verwandte Themen