2014-10-15 9 views
8

auf dieser interessanten Frage Basierend: Addition of int and uint und um mit konstantem Falten liebäugelt wie in Nicholas Carey'sanswer erwähnt, habe ich auf ein scheinbar inkonsistentes Verhalten des Compilers gestolpert:uint und int und konstantes Falten Subtrahierend

des Betrachten folgende Code-Schnipsel:

int i = 1; 
uint j = 2; 
var k = i - j; 

Hier löst der Compiler korrekt k-long. Dieses spezielle Verhalten ist in den Spezifikationen gut definiert, wie in den Antworten auf die zuvor erwähnte Frage erläutert.

Was überraschend für mich war, ist, dass das Verhalten ändert, wenn sie mit wörtlichen Konstanten oder Konstanten im Allgemeinen zu tun. Lesen Nicholas Careys answer erkannte ich, dass das Verhalten unvereinbar sein könnten, so hab ich gecheckt und sicher genug:

const int i = 1; 
const uint j = 2; 
var k = i - j; //Compile time error: The operation overflows at compile time in checked mode. 
k = 1 - 2u; //Compile time error: The operation overflows at compile time in checked mode. 

k in diesem Fall gelöst Uint32.

Gibt es einen Grund dafür, dass das Verhalten bei Konstanten anders ist oder ist das ein kleiner, aber unglücklicher "Fehler" (Fehlen eines besseren Begriffs) im Compiler?

+2

Bei einer Schätzung führt der Compiler keine impliziten Konvertierungen für Konstanten. – Powerlord

+0

@Powerlord Nun, es muss, schließlich konvertiert es implizit "int" zu "uint". – InBetween

+1

Die Spezifikation berücksichtigt dies jedoch ... §6.1.9 Implizite konstante Ausdrucksumwandlungen: "Ein konstanter Ausdruck (§7.19) vom Typ int kann in den Typ' sbyte', 'byte',' short', 'konvertiert werden ushort', 'uint' oder' ulong', vorausgesetzt, der Wert des Konstantenausdrucks liegt innerhalb des Bereichs des Zieltyps. " Immer noch versuchen zu finden, was es für Literale und/oder konstante Variablen sagt. – Powerlord

Antwort

3

Schauen Sie sich diese Antwort here

Das Problem ist, dass Sie const verwenden.

Zur Laufzeit wenn es ein const gibt, ist das Verhalten genau wie bei Literalen, oder als hättest du einfach diese Zahlen im Code codiert, also da die Zahlen 1 und 2 sind, wird es auf einen Uint32 umgeschrieben, da 1 ist im Bereich von uint32. Dann, wenn Sie versuchen, 1 - 2 mit uint32 zu subtrahieren, überläuft es, seit 1u - 2u = +4.294.967.295 (0xFFFFFFFF).

Der Compiler darf Litterals betrachten und sie anders interpretieren als andere Variablen. Da sich const niemals ändert, kann es Garantien geben, die es sonst nicht machen könnte. in diesem Fall kann es garantieren, dass 1 innerhalb des Bereichs einer Uint ist, deshalb kann es es implizit darstellen. Unter normalen Umständen (ohne const) kann diese Garantie nicht übernommen werden,

ein signed int reicht von -2.147.483.648 (0x80000000) bis +2.147.483.647 (0x7FFFFFFF).

ein unsigned int reicht von 0 (0x00000000) bis +4.294.967.295 (0xFFFFFFFF).

Moral der Geschichte, seien Sie vorsichtig, wenn Sie const und var mischen, können Sie etwas bekommen, was Sie nicht erwarten.

+0

Richtig, derp, das Problem ist mit der 'var', nicht die Konstante. Beschreibe, dass du den falschen Weg einschlagen musst, wenn du durch die Spezifikation schaust. – Powerlord

+0

Verwendung von 'var' ist hier nicht das Problem, da es ein Fehler bei der Kompilierung ist. In echtem Code würde ich niemals 'var' in einem Ausdruck verwenden, in dem der Typ auf den ersten Blick nicht kristallklar ist. Und ich weiß, dass die Verwendung von 'const' oder * konstanten Literalen * dasselbe Verhalten haben wird. Meine Frage ist * warum * dieses Verhalten ist inkonsistent mit dem allgemeinen, wo Variablen beteiligt sind. – InBetween

+0

@Powerlord Nein, 'var' ist nicht das Problem. 'long k = 1 - 2u;' ist auch ein Kompilierzeitfehler. In C# spielt der Rückgabetyp niemals eine Rolle bei der Überladungsauflösung. Warum sollte "Var" also Teil des Problems sein?Das Problem ist, warum '1 - 2u' in 'uint' aufgelöst wird, wenn es um * Konstanten * geht. – InBetween

4

Vom C# specification version 5, Abschnitt 6.1.9, Constant Ausdrücke nur erlauben, den folgenden impliziten Konvertierungen

6.1.9 Implicit konstanten Ausdruck Konvertierungen
Eine implizite konstante Ausdruck Umwandlung ermöglicht, daß die folgenden Umwandlungen:
* A konstanter Ausdruck (§7.19) vom Typ int kann zu konvertierenden Typ sbyte, byte, short, ushort, uint oder ulong, um den Wert des Konstantausdruck vorgesehen ist im Bereich des Zieltyps.
• Ein Konstantenausdruck vom Typ long kann in den Typ ulong konvertiert werden, vorausgesetzt, der Wert des Konstantenausdrucks ist nicht negativ.

Beachten Sie, dass long ist nicht auf der Liste der int Konvertierungen.

Die andere Hälfte das Problem ist, dass nur eine geringe Anzahl von numerischen Förderungen für binäre Operationen geschehen:

(Aus Abschnitt 7.3.6.2 Binary numerische Promotions):

  • Wenn entweder Operanden vom Typ dezimal wird der andere Operand in dezimal konvertiert, oder es tritt ein Bindungszeitfehler auf, wenn der andere Operand vom Typ float oder double ist.
  • Andernfalls, wenn einer der Operanden vom Typ double ist, wird der andere Operand in double konvertiert.
  • Wenn der andere Operand vom Typ float ist, wird der andere Operand in float konvertiert.
  • Andernfalls, wenn einer der Operanden vom Typ ulong ist, wird der andere Operand in den Typ ulong konvertiert oder es tritt ein Bindungszeitfehler auf, wenn der andere Operand vom Typ sbyte, short, int oder long ist.
  • Andernfalls, wenn einer der Operanden vom Typ long ist, wird der andere Operand in den Typ long konvertiert.
  • Andernfalls, wenn einer der Operanden vom Typ uint ist und der andere Operand vom Typ sbyte, short oder int ist, werden beide Operanden in den Typ long konvertiert.
  • Andernfalls, wenn einer der Operanden vom Typ Uint ist, wird der andere Operand in den Typ Uint konvertiert.
  • Andernfalls werden beide Operanden in den Typ int konvertiert.

ERINNERUNG: Die int zu long Umwandlung ist für Konstanten verboten, was bedeutet, dass beide args stattdessen uint s gefördert werden.

+0

Übrigens gibt es keinen Hinweis darauf, warum 'int' konstante Ausdrücke nicht in' long' umgewandelt werden können ... oder irgendeine Diskussion darüber, ob 'uint' Konstanten überhaupt konvertiert werden können ... und keine Erklärung warum in beiden dieser Fälle. – Powerlord