Warum erlaubt C++ die implizite Konvertierung von int zu unsigned int?

Lesezeit: 8 Minuten

Benutzer-Avatar
Nefarel NefX

Betrachten Sie folgenden Code:

void foo(unsigned int x)
{

}

int main()
{
  foo(-5);
  return 0;
}

Dieser Code lässt sich ohne Probleme kompilieren. Fehler wie dieser können viele Probleme verursachen und sind schwer zu finden. Warum erlaubt C++ eine solche Konvertierung?

  • Banale Antwort: weil C++ so konzipiert wurde, dass es (größtenteils) abwärtskompatibel mit C ist, und C implizite Umwandlungen zwischen ganzzahligen Typen erlaubt.

    – Benutzer168715

    10. März 2011 um 17:20 Uhr

  • Interessanterweise warnen die meisten Compiler, wenn Sie vergleichen int mit unsigned intwie in i < ui

    – Nawaz

    10. März 2011 um 17:21 Uhr


  • @ user168715: das ergibt keinen Sinn. Warnung bedeutet nicht, dass es Ihnen nicht erlaubt ist. Es bedeutet lediglich, dass es ein Problem bei der impliziten Konvertierung geben könnte!

    – Nawaz

    10. März 2011 um 17:22 Uhr


  • @Nawaz: Die Frage ist “Warum [does] C++ erlaubt eine solche Konvertierung“; „Warnung“ erscheint nirgendwo im Originaltitel oder in der Frage.

    – Benutzer168715

    10. März 2011 um 17:29 Uhr

  • Leute, Nawaz hat eine interessante Beobachtung gemacht, keinen Erklärungsversuch. Kühlen Sie Ihre Jets.

    – Matt K

    10. März 2011 um 17:36 Uhr

Benutzer-Avatar
Markus B

Die kurze Antwort lautet, weil C solche Konvertierungen ursprünglich unterstützte und sie vorhandene Software in C++ nicht beschädigen wollten.

Beachten Sie, dass einige Compiler davor warnen. Zum Beispiel g++ -Wconversion wird vor diesem Konstrukt warnen.

In vielen Fällen ist die implizite Konvertierung sinnvoll, zum Beispiel wenn int wurde in Berechnungen verwendet, aber das Endergebnis wird niemals negativ sein (aus dem Algorithmus bekannt und optional geltend gemacht).

BEARBEITEN: Zusätzliche wahrscheinliche Erklärung: Denken Sie daran, dass C ursprünglich eine viel lockerer typisierte Sprache war als C++ jetzt. Mit Funktionsdeklarationen im K&R-Stil hätte der Compiler keine Möglichkeit gehabt, solche impliziten Konvertierungen zu erkennen, also warum sich die Mühe machen, sie in der Sprache einzuschränken. Ihr Code würde zum Beispiel ungefähr so ​​aussehen:

int foo(x)
unsigned int x
{

}

int main()
{
  foo(-5);
  return 0;
}

während die Erklärung allein gewesen wäre int foo(x);

Der Compiler verließ sich tatsächlich darauf, dass der Programmierer die richtigen Typen in jeden Funktionsaufruf übergab, und führte keine Konvertierungen durch am Aufrufort. Wenn die Funktion dann tatsächlich aufgerufen wurde, wurden die Daten auf dem Stack (usw.) so interpretiert, wie die Funktionsdeklaration angegeben ist.

Sobald Code geschrieben wurde, der sich auf diese Art der impliziten Konvertierung stützte, wäre es viel schwieriger geworden, ihn aus ANSI C zu entfernen, selbst wenn Funktionsprototypen mit tatsächlichen Typinformationen hinzugefügt wurden. Dies ist wahrscheinlich der Grund, warum es auch jetzt noch in C bleibt. Dann kam C++ und entschied sich erneut dafür, die Abwärtskompatibilität mit C nicht zu brechen und solche impliziten Konvertierungen weiterhin zuzulassen.

  • Aktivieren Sie für MSVC 4365 „signed/unsigned mismatch“, um dies zu überprüfen, es war hilfreich für meinen Code.

    – geschmolzen

    2. Oktober 2016 um 5:39 Uhr

  • Nur eine weitere Eigenart einer Sprache, die viele dumme Eigenarten hat.
  • Die Konvertierung ist gut definiert, um sie zu umschließen, was in einigen Fällen nützlich sein kann.
  • Es ist abwärtskompatibel mit C, was dies aus den oben genannten Gründen tut.

Treffen Sie Ihre Wahl.

Benutzer-Avatar
j4x

@ user168715 hat recht. C++ wurde ursprünglich als Obermenge von C, vorgeben, so abwärtskompatibel wie möglich zu sein. Die “C”-Philosophie besteht darin, die meiste Verantwortung dem Programmierer zu übertragen, anstatt gefährliche Dinge zu verbieten. Für C-Programmierer ist es der Himmel, für Java-Programmierer die Hölle… Geschmackssache.

Ich werde die Standards ausgraben, um zu sehen, wo genau es geschrieben steht, aber ich habe im Moment keine Zeit dafür. Ich werde meine Antwort so schnell wie möglich bearbeiten.

Ich stimme auch zu, dass ein Teil der geerbten Freiheit zu Fehlern führen kann, die wirklich schwer zu debuggen sind, also füge ich dem Gesagten hinzu, dass Sie in g ++ eine Warnung aktivieren können, um Sie vor dieser Art von Fehlern zu bewahren: -Wconversion Flagge.

-W-Konvertierung

Warnung vor impliziten Konvertierungen, die einen Wert ändern können. Dazu gehören Konvertierungen zwischen Real und Integer, wie abs (x), wenn x doppelt ist; Konvertierungen zwischen signiert und unsigned, wie unsigned ui = -1; und Konvertierungen in kleinere Typen wie sqrtf (M_PI). Warnen Sie nicht bei expliziten Umwandlungen wie abs ((int) x) und ui = (unsigned) -1 oder wenn der Wert durch die Konvertierung nicht geändert wird, wie in abs (2.0). Warnungen zu Konvertierungen zwischen vorzeichenbehafteten und vorzeichenlosen Ganzzahlen können mit -Wno-sign-conversion deaktiviert werden.

Für C++ warnen Sie auch vor verwirrender Überladungsauflösung für benutzerdefinierte Konvertierungen; und Konvertierungen, die niemals einen Typkonvertierungsoperator verwenden: Konvertierungen in void, denselben Typ, eine Basisklasse oder einen Verweis darauf. Warnungen zu Konvertierungen zwischen vorzeichenbehafteten und vorzeichenlosen Ganzzahlen sind in C++ standardmäßig deaktiviert, es sei denn, -Wsign-conversion ist explizit aktiviert.

Andere Compiler können ähnliche Flags haben.

  • Aktivieren Sie für MSVC 4365 „signed/unsigned mismatch“, um dies zu überprüfen, es war hilfreich für meinen Code.

    – geschmolzen

    2. Oktober 2016 um 5:39 Uhr

Zur Zeit des ursprünglichen C-Standards wurde die Konvertierung bereits von vielen (allen?) Compilern erlaubt. Basierend auf dem C-Grundprinzip scheint es wenig (wenn überhaupt) Diskussionen darüber gegeben zu haben, ob solche impliziten Konvertierungen erlaubt sein sollten. Als C++ auf den Markt kam, waren solche impliziten Konvertierungen so weit verbreitet, dass ihre Beseitigung die Sprache mit einem Großteil des C-Codes inkompatibel gemacht hätte. Es würde wahrscheinlich haben C++ sauberer gemacht; es würde sicherlich haben es viel seltener verwendet — bis zu dem Punkt, dass es wahrscheinlich nie über die Stufe “C mit Klassen” hinausgekommen wäre, und selbst das wäre nur eine meist ignorierte Fußnote in der Geschichte der Bell-Labore.

Die einzige wirkliche Frage in dieser Richtung war zwischen den Regeln “Werterhaltung” und “Vorzeichenerhaltung ohne Vorzeichen” bei der Förderung von unsignierten Werten, die “kleiner” als int sind. Der Unterschied zwischen den beiden entsteht, wenn (zum Beispiel) ein unsigned short zu einem unsigned char hinzugefügt wird.

Unsigned Preserving Rules besagen, dass Sie beide zu unsigned int hochstufen. Werterhaltende Regeln besagen, dass Sie beide Werte fördern int, wenn es kann alle Werte des ursprünglichen Typs darstellen (z. B. den üblichen Fall von 8-Bit-Char, 16-Bit-Short und 32-Bit-Int). Auf der anderen Seite, wenn int und short beide 16 Bit sind, also int nicht alle Werte von unsigned short darstellen kann, dann stufen Sie unsigned short zu unsigned int hoch (beachten Sie, dass es immer noch als Promotion betrachtet wird, obwohl es nur passiert, wenn es wirklich so ist nicht eine Werbeaktion — dh die beiden Typen haben die gleiche Größe).

Auf Gedeih und Verderb (und es wurde oft in beide Richtungen argumentiert) entschied sich das Komitee für werterhaltende und nicht für unsignierte erhaltende Beförderungen. Beachten Sie jedoch, dass es sich hierbei um eine Konvertierung in die entgegengesetzte Richtung handelt: Statt von signiert nach unsigniert geht es darum, ob Sie unsigniert in signiert konvertieren.

Denn der Standard erlaubt eine implizite Konvertierung von signed zu unsigned Typen.

Ebenfalls (int)a + (unsigned)b Ergebnisse zu unsigned – Dies ist ein C++-Standard.

  • “Warum erlaubt C++ das?” “Weil C++ dies zulässt”. Was für ein nicht hilfreicher Müll. Ich würde Sie herabstimmen, wenn ich nicht meine tägliche Stimmobergrenze erreicht hätte.

    – Leichtigkeitsrennen im Orbit

    10. März 2011 um 17:21 Uhr

  • @artyom.stv: Natürlich stimme ich dem Standard zu. Die Frage dreht sich um warum die norm sagt das.

    – Leichtigkeitsrennen im Orbit

    10. März 2011 um 17:27 Uhr

  • @artyom.stv: Warum gibt es auf solche Fragen keine guten Antworten? Der Standard wurde nicht von Gott geschrieben, es gibt Gründe, warum er sagt, was er sagt, auch wenn der Grund darauf hinausläuft, „weil Person X an Tatsache Y geglaubt hat, was eigentlich falsch ist, und es zu spät ist, sich jetzt zu ändern“. Zugegebenermaßen hat bisher noch niemand die C-Motivation angeboten.

    – Steve Jessop

    10. März 2011 um 17:30 Uhr


  • @artyom: Bjarne hat a geschrieben Buchen über die Gründe für Entscheidungen, die beim Design von C++ getroffen wurden. Indem wir es lesen, können wir seine Beweggründe erkennen, zumindest soweit wir darauf vertrauen, dass er sich an sie erinnert. Sie können auch fragen, wie ich wissen kann, was der Standard selbst sagt, ohne ihn entwickelt zu haben. Ich habe eine Kopie, so funktioniert menschliche Kommunikation 😉

    – Steve Jessop

    10. März 2011 um 17:32 Uhr


  • @artyom: hängt davon ab, warum der Fragesteller gefragt hat. Diese Antwort provoziert sicherlich die Frage: “Nun, warum lässt C das dann zu?”, und ich denke, das ist der Grund, warum user168715 den Kommentar selbst als “banal” bezeichnet hat.

    – Steve Jessop

    10. März 2011 um 17:36 Uhr

  • “Warum erlaubt C++ das?” “Weil C++ dies zulässt”. Was für ein nicht hilfreicher Müll. Ich würde Sie herabstimmen, wenn ich nicht meine tägliche Stimmobergrenze erreicht hätte.

    – Leichtigkeitsrennen im Orbit

    10. März 2011 um 17:21 Uhr

  • @artyom.stv: Natürlich stimme ich dem Standard zu. Die Frage dreht sich um warum die norm sagt das.

    – Leichtigkeitsrennen im Orbit

    10. März 2011 um 17:27 Uhr

  • @artyom.stv: Warum gibt es auf solche Fragen keine guten Antworten? Der Standard wurde nicht von Gott geschrieben, es gibt Gründe, warum er sagt, was er sagt, auch wenn der Grund darauf hinausläuft, „weil Person X an Tatsache Y geglaubt hat, was eigentlich falsch ist, und es zu spät ist, sich jetzt zu ändern“. Zugegebenermaßen hat bisher noch niemand die C-Motivation angeboten.

    – Steve Jessop

    10. März 2011 um 17:30 Uhr


  • @artyom: Bjarne hat a geschrieben Buchen über die Gründe für Entscheidungen, die beim Design von C++ getroffen wurden. Indem wir es lesen, können wir seine Beweggründe erkennen, zumindest soweit wir darauf vertrauen, dass er sich an sie erinnert. Sie können auch fragen, wie ich wissen kann, was der Standard selbst sagt, ohne ihn entwickelt zu haben. Ich habe eine Kopie, so funktioniert menschliche Kommunikation 😉

    – Steve Jessop

    10. März 2011 um 17:32 Uhr


  • @artyom: hängt davon ab, warum der Fragesteller gefragt hat. Diese Antwort provoziert sicherlich die Frage: “Nun, warum lässt C das dann zu?”, und ich denke, das ist der Grund, warum user168715 den Kommentar selbst als “banal” bezeichnet hat.

    – Steve Jessop

    10. März 2011 um 17:36 Uhr

1018860cookie-checkWarum erlaubt C++ die implizite Konvertierung von int zu unsigned int?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy