Frage

In mehreren modernen Programmiersprachen (wie C ++, Java und C #), kann die Sprache Integer-Überlauf zur Laufzeit auftreten, ohne jede Art von Fehlerzustand zu erhöhen.

Betrachten wir zum Beispiel diese (erfundene) C # Methode, die für die Möglichkeit der Überlauf / Unter nicht berücksichtigt. (Der Kürze halber auch das Verfahren nicht den Fall behandeln, in denen die angegebenen Liste ist ein NULL-Verweis).

//Returns the sum of the values in the specified list.
private static int sumList(List<int> list)
{
    int sum = 0;
    foreach (int listItem in list)
    {
        sum += listItem;
    }
    return sum;
}

Wenn diese Methode aufgerufen wird, wie folgt:

List<int> list = new List<int>();
list.Add(2000000000);
list.Add(2000000000);
int sum = sumList(list);

Ein Überlauf wird in dem sumList() Verfahren auftritt (weil der int Typ in C # 32-Bit-Ganzzahl mit Vorzeichen ist, und die Summe der Werte in der Liste überschreitet den Wert der maximalen 32-Bit-Ganzzahl mit Vorzeichen). Die Summe Variable einen Wert von -294.967.296 (ein Wert von 4000000000); dies wahrscheinlich nicht das, was der (hypothetische) Entwickler der Summe Methode bestimmt.

Natürlich gibt es verschiedene Techniken, die von Entwicklern verwendet werden können, die Möglichkeit einer Integer-Überlauf, wie unter Verwendung eines Typ wie Java BigInteger oder die checked Stichwort und /checked Compiler-Schalter in C #.

Allerdings ist die Frage, die mich interessiert ist, warum diese Sprachen standardmäßig entworfen wurden, erlauben ganz Zahl an erster Stelle geschehen überläuft, statt zum Beispiel eine Ausnahme erhöhen, wenn eine Operation zur Laufzeit durchgeführt wird, das wäre führen zu einem Überlauf. Es scheint, wie ein solches Verhalten würde Fehler in Fällen helfen zu vermeiden, dass ein Entwickler die Möglichkeit der Überlauf zu berücksichtigen vernachlässigt, wenn das Schreiben von Code, der eine arithmetische Operation durchführt, die in Überlauf führen kann. (Diese Sprachen so etwas wie eine „ungeprüft“ Stichwort enthalten sein können, die einen Block bezeichnen könnte, wo Integer-Überlauf zulässig ist, ohne eine Ausnahme auftreten angehoben werden, in jenen Fällen, in denen das Verhalten explizit durch den Entwickler bestimmt ist, C # eigentlich erledigt diese haben.)

Ist die Antwort einfach einkochen, um die Leistung - die Sprache Designer wollten nicht ihre jeweiligen Sprachen mit „langsamen“ arithmetischen Integer-Operationen auf dem Standard, wo die Laufzeit zusätzliche Arbeit tun, müßte geprüft werden, ob ein Überlauf aufgetreten ist, auf jede anwendbare arithmetische Operation - und diese Leistung Berücksichtigung überwogen den Wert von „silent“ Fehler in dem Fall zu vermeiden, dass ein versehentlicher Überlauf auftritt

?

Gibt es andere Gründe für diese Sprache Design-Entscheidung auch, anders als Leistungsinformationen?

War es hilfreich?

Lösung

In C #, es war eine Frage der Leistung. Insbesondere out-of-Box-Benchmarking.

Wenn C # neu war, Microsoft hatte gehofft, dass eine Menge von C ++ Entwickler schalten würde. Sie wussten, dass viele C ++ Leute gedacht C ++, so schnell zu sein, vor allem schneller als Sprache, dass „verschwendet“ Zeit auf automatische Speicherverwaltung und dergleichen.

Sowohl potentiell Adoptiveltern und Magazin Rezensenten sind wahrscheinlich eine Kopie des neuen C # erhalten, installieren Sie es, baut eine triviale Anwendung, die niemand jemals in der realen Welt schreiben würde, es in einer engen Schleife laufen und messen, wie lange es dauerte. Dann würden sie eine Entscheidung für ihr Unternehmen machen oder einen Artikel veröffentlichen auf der Grundlage dieses Ergebnis.

Die Tatsache, dass ihr Test zeigte, C # langsamer als nativ kompilierten C ++ die Art der Sache ist, dass die Menschen aus C # schnell drehen würde. Die Tatsache, dass Ihre C # app Überlauf fangen wird / Unterschreitung automatisch die Art der Sache, dass sie verpassen könnte. Also, es ist standardmäßig deaktiviert.

Ich denke, es ist offensichtlich, dass 99% der Zeit, die wir wollen / geprüft auf sein. Es ist ein unglücklicher Kompromiss.

Andere Tipps

Ich denke, Leistung ein ziemlich guter Grund. Wenn Sie jede Anweisung in einem typischen Programm betrachten, die eine ganze Zahl erhöht, und wenn man statt dem einfachen op hinzufügen 1 hatte es jedes Mal zu überprüfen, ob ein Hinzufügen den Typen überlaufen würde, dann die Kosten in zusätzlichen Zyklen wären ziemlich schwerwiegend sein.

Sie arbeiten unter der Annahme, dass Integer-Überlauf ist immer unerwünschtes Verhalten.

Manchmal Integer-Überlauf wird das Verhalten gewünscht. Ein Beispiel I gesehen haben, ist Repräsentation eines absoluten Wertes Überschrift als Festpunktzahl. Bei einem gegebenen unsigned int, 0 0 oder 360 Grad und die maximalen 32-Bit-Integer ohne Vorzeichen (0xffffffff) ist der größte Wert knapp unter 360 Grad.

int main()
{
    uint32_t shipsHeadingInDegrees= 0;

    // Rotate by a bunch of degrees
    shipsHeadingInDegrees += 0x80000000; // 180 degrees
    shipsHeadingInDegrees += 0x80000000; // another 180 degrees, overflows 
    shipsHeadingInDegrees += 0x80000000; // another 180 degrees

    // Ships heading now will be 180 degrees
    cout << "Ships Heading Is" << (double(shipsHeadingInDegrees) / double(0xffffffff)) * 360.0 << std::endl;

}

Es gibt wahrscheinlich auch andere Situationen, in denen Überlauf in diesem Beispiel akzeptabel, ähnlich ist.

C / C ++ nie trap Verhalten Mandat. Auch die offensichtliche Division durch 0 ist nicht definiertes Verhalten in C ++, nicht eine spezifizierte Art Falle.

Die Sprache C hat keinen Begriff des Trapping, wenn Sie Signale zählen.

C ++ hat ein Konstruktionsprinzip, dass es nicht Aufwand nicht in C einführt, wenn Sie danach fragen. So würde Stroustrup nicht gesucht haben Mandat, dass ganze Zahlen in einer Weise verhalten, die eine explizite Kontrolle erfordert.

Einige frühe Compiler und leichte Implementierungen für eingeschränkte Hardware nicht unterstützt Ausnahmen überhaupt, und Ausnahmen können oft mit Compiler-Optionen deaktiviert werden. Mandatierung Ausnahmen für Sprache Einbauten problematisch wäre.

Auch wenn C ++ ganze Zahlen gemacht hatte geprüft, 99% der Programmierer in den frühen Tagen, wenn off für die Leistungssteigerung worden wäre ...

Da für Überlauf überprüft Zeit in Anspruch nimmt. Jede primitive mathematische Operation, die normalerweise in eine einzige Montageanleitung übersetzt würde muß einen Scheck für Überlauf, in mehrere Montageanleitung führte, was möglicherweise in einem Programm, das mehrmals langsamer ist.

Es ist wahrscheinlich, 99% mehr Leistung. Auf x86 hätte den Überlauf-Flag auf jeder Operation zu überprüfen, die eine große Leistung getroffen wären.

Das andere 1% würde jene Fälle, in denen Menschen Phantasie Bit Manipulationen tun oder ‚ungenau‘ sind in Mischen und ohne Vorzeichen Operationen und will die Überlauf-Semantik.

Die Abwärtskompatibilität ist ein großer. Mit C wurde davon ausgegangen, dass Sie genügend Aufmerksamkeit auf die Größe Ihrer Datentypen wurden zahlen, die, wenn ein Über- / Unterschreitung aufgetreten, dass das war, was man wollte. Dann mit C ++, C # und Java, sehr wenig verändert mit, wie die „eingebauten“ Datentypen gearbeitet.

Ihr Verständnis, warum Fehler würden nicht standardmäßig zur Laufzeit erhöht werden, läuft darauf hinaus, das Erbe nach unten von dem Wunsch, Programmiersprachen mit ACID-ähnlichem Verhalten zu schaffen. Insbesondere ist der Grundsatz, dass alles, was Sie es zu tun kodieren (oder nicht-Code), wird es tun (oder nicht). Wenn Sie nicht einige Fehler-Handler-Code haben, dann wird die Maschine „annehmen“ auf Grund keine Fehlerbehandlung, dass Sie wirklich das lächerliche, crash-anfällig, was tun mögen Sie sagen, es zu tun.

(ACID-Referenz: http://en.wikipedia.org/wiki/ACID )

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top