2009-05-07 11 views
1

Betrachten Sie den folgenden Code ein:Übliche arithmetische Konvertierung - ein besseres Regelwerk?

void f(byte x) {print("byte");} 
void f(short x) {print("short");} 
void f(int x) {print("int");} 

void main() { 
    byte b1, b2; 
    short s1, s2; 

    f(b1 + b2); // byte + byte = int 
    f(s1 + s2); // short + short = int 
} 

In C++, C#, D und Java, die beide Funktion resolve zu den "int" Überlastungen ruft ... ich realisieren bereits dies "in den Spezifikationen", Aber warum sind Sprachen so gestaltet? Ich suche nach einem tieferen Grund.

Für mich macht es Sinn, für das Ergebnis der kleinste Art der Lage sein, alle möglichen Werte der beiden Operanden zu repräsentieren, zum Beispiel:

byte + byte --> byte 
sbyte + sbyte --> sbyte 
byte + sbyte --> short 
short + short --> short 
ushort + ushort --> ushort 
short + ushort --> int 
// etc... 

Dies würde unbequem Code beseitigen wie short s3 = (short)(s1 + s2), wie Auch IMO ist viel intuitiver und leichter zu verstehen.

Ist dies ein übriggebliebenes Vermächtnis aus den Tagen von C, oder gibt es bessere Gründe für das aktuelle Verhalten?

+0

Ich werde feststellen, dass jedes Programm mit "void main()" ist durch die C-und C++ - Standards nicht definiert, und Sie haben keinen Grund, sich über irgendetwas zu beschweren. Verwenden Sie "int main()", wenn Sie standardisiertes Verhalten diskutieren wollen. –

+0

Ich erwähnte andere Sprachen außer C und C++. Betrachten Sie das als nur Pseudo-Code und nichts mehr. Nach geringfügigen Änderungen (z. B. void nach int ändern, und Byte nach char und printf drucken usw.), kompiliert es in jeder C-ähnlichen Sprache und zeigt das beschriebene Verhalten. Sicher haben Sie nicht erwartet, dass dieselbe unmodifizierte Quelldatei in allen erwähnten Sprachen kompiliert wird, oder? – zildjohn01

Antwort

2

von this MSDN blog post zitiert:

byte b = 32; Byte c = 240; int i = b + c; // was bin ich?

In dieser Fantasy-Welt wäre der Wert von i 16! Warum? Da die beiden Operanden zum + Operator beide Bytes sind, wird also die Summe "b + c" als ein Byte berechnet, was aufgrund von Integer-Überlauf 16 ergibt. (Und, wie ich bereits erwähnt, Integer-Überlauf ist das neue Sicherheitsangriffsvektor.)

ähnlich

int j = -b;

würde aus dem gleichen Grund in j den Wert 224 und nicht -32 ergeben.

Ist das wirklich was du willst?

...

Also egal, wie Sie es drehen, sind Sie ärgerlich Abgüsse einzufügen gehen zu müssen. Kann auch die Sprache haben Fehler auf der Seite der Sicherheit (zwingt Sie , die Casts, wo Sie eingeben, dass Überlauf kein Problem ist) als Fehler auf der Seite der Stille (wo Sie möglicherweise nicht die fehlende beachten wirft bis Ihre Gehaltsabrechnung fragt Sie, warum ihre Bücher nicht am Ende der des Monats summieren.

Es ist auch erwähnenswert, dass das Hinzufügen in diesen Casts nur zusätzliche Eingabe bedeutet, und nichts mehr. Sobald der JIT (oder möglicherweise der statische Compiler selbst) die arithmetische Operation auf eine grundlegende Prozessoranweisung reduziert, ist nichts schlaues passiert - es ist nur, ob die Nummer als int oder byte behandelt wird.

Dies ist eine gute Frage, aber ... überhaupt nicht offensichtlich. Hoffnung, die die Gründe für Sie jetzt klar macht.

+1

Kommen wir ein Jahr später zurück ... Ich finde, dass ich viel mehr mit den Kommentaren zu diesem Artikel mitschwinge als mit dem Artikel selbst. Naja, zumindest verstehe ich die Designentscheidung. – zildjohn01

+0

Wie unterscheiden sich die Typen "Umbruch" und "Non-Wrapping" mit der Regel, dass die Umbrucharten nicht in andere numerische Typen konvertiert werden können, aber über eine Funktion oder Eigenschaft verfügen, um die kleinste nicht negative Zahl zu melden auf Null, ergibt einen gegebenen Wert oder sonst den Wert der kleinsten Größe, der, wenn er zu Null addiert wird, einen gegebenen Wert ergeben wird. Dann würde '(240wb + 255wb) .AsUnsigned' die Zahl 239 ergeben und' (240wb + 255wb) .AsSigned' würde die Zahl -17 ergeben. Ich denke, dass alle Fälle, die kompiliert werden, eindeutig erwartetes Verhalten ergeben. – supercat

0

Ein besseres Regelwerk IMHO, wenn man vorsieht, dass die Verschiebeoperatoren nur mit konstanten Verschiebungswerten verwendet werden können (verwenden Sie Verschiebefunktionen für variable Verschiebungsbeträge), müssten die Ergebnisse jedes arithmetischen Ausdrucks immer so ausgewertet werden Es wurde mit dem größtmöglichen signierten oder unsignierten Typ verarbeitet, vorausgesetzt, es konnte entweder statisch garantiert werden, dass korrekte Ergebnisse erzielt wurden (leicht knifflige Regeln würden in Fällen gelten, in denen der größte signierte Typ möglicherweise nicht ausreichend ist). Da die angegebenen Shift-Operanden nur Konstanten sein dürfen, könnte man zum Kompilierungszeitpunkt ziemlich einfach feststellen, was der größte bedeutungsvolle Wert eines Operanden sein könnte. Daher sehe ich keinen guten Grund für Compiler, nicht zu schauen, wie das Ergebnis eines Operators verwendet wird bei der Entscheidung über die Implementierung des Betreibers.