Warum muss in C und C++ vor arithmetischen Operationen ein short in ein int umgewandelt werden?

Lesezeit: 8 Minuten

Warum muss in C und C vor arithmetischen Operationen ein
Dayuloli

Aus den Antworten, die ich auf diese Frage erhalten habe, geht hervor, dass C++ diese Anforderung für die Konvertierung von geerbt hat short hinein int bei der Durchführung von arithmetischen Operationen von C. Darf ich Ihnen den Kopf darüber zerbrechen warum wurde dies überhaupt erst in C eingeführt? Warum führen Sie diese Operationen nicht einfach so durch short?

Zum Beispiel (entnommen aus dyps Vorschlag in den Kommentaren):

short s = 1, t = 2 ;
auto  x = s + t ;

x wird Typ haben int.

  • @Jefffrey Integral Promotion ist Teil der üblichen arithmetischen Umrechnungen. short s=1, t=2; auto x = s+t; dann x ist ein int.

    – dyp

    23. Juni 2014 um 17:38 Uhr

  • maxkurz + maxkurz > maxkurz

    – Technosaurus

    23. Juni 2014 um 17:53 Uhr

  • @technosaurus das würde nicht erklären warum int wird nicht befördert long (maxint + maxint > maxint).

    – Schuh

    23. Juni 2014 um 18:16 Uhr

  • Ich verstehe die Downvotes zu dieser Frage nicht. Dies ist eine gute Frage mit einer interessanten Antwort. Vier Downvotes und keine Kommentare sind ziemlich entmutigend.

    – Shafik Yaghmour

    24. Juni 2014 um 1:26 Uhr

  • @dyp: Die Regeln für das Warum x Typ ist int sind in C und C++ aber völlig unterschiedlich… 😉

    – Deduplizierer

    7. Juli 2014 um 12:43 Uhr

Warum muss in C und C vor arithmetischen Operationen ein
Shafik Yaghmur

Betrachten wir die Begründung für International Standard – Programmiersprachen – C im Abschnitt 6.3.1.8 Übliche arithmetische Umrechnungen es sagt (Hervorhebung von mir für die Zukunft):

Die Regeln im Standard für diese Konvertierungen sind leichte Modifikationen von denen in K&R: Die Modifikationen berücksichtigen die hinzugefügten Typen und die werterhaltenden Regeln. Es wurde eine explizite Lizenz hinzugefügt, um Berechnungen in einem „breiteren“ Typ als unbedingt erforderlich durchzuführen, da dies manchmal zu kleinerem und schnellerem Code führen kann, ganz zu schweigen von der häufigeren richtigen Antwort. Berechnungen können auch in einer “engeren” Art durch die Als-ob-Regel durchgeführt werden, solange das gleiche Endergebnis erhalten wird. Explizites Casting kann immer verwendet werden, um einen Wert in einem gewünschten Typ zu erhalten

Abschnitt 6.3.1.8 von dem Entwurf des C99-Standards deckt die ab Übliche arithmetische Umrechnungen die auf Operanden von arithmetischen Ausdrücken zum Beispiel Abschnitt angewendet wird 6.5.6 Additive Operatoren sagt:

Wenn beide Operanden vom arithmetischen Typ sind, wird die übliche arithmetische Umrechnungen werden an ihnen durchgeführt.

Wir finden ähnlichen Text in Abschnitt 6.5.5 Multiplikative Operatoren auch. Im Falle eines kurz Operand, zuerst die ganzzahlige Aktionen werden ab Abschnitt angewendet 6.3.1.1 Boolesche Werte, Zeichen und ganze Zahlen was sagt:

Wenn ein int alle Werte des ursprünglichen Typs darstellen kann, wird der Wert in einen int konvertiert; andernfalls wird es in ein unsigned int umgewandelt.
Diese werden als Integer-Promotions bezeichnet.48) Alle anderen Typen bleiben von den Integer-Promotions unverändert.

Die Diskussion aus Abschnitt 6.3.1.1 des Begründung oder Internationaler Standard – Programmiersprachen – C an ganzzahlige Aktionen ist eigentlich interessanter, ich werde selektiv zitieren, weil es zu lang ist, um es vollständig zu zitieren:

Implementierungen fielen hinein zwei große Lager was charakterisiert werden kann als unsigned Erhaltung und Werterhaltung.

[…]

Die unsigned konservierender Ansatz fordert die Heraufstufung der beiden kleineren unsigned-Typen auf unsigned int. Dies ist eine einfache Regel und ergibt einen Typ, der von der Ausführungsumgebung unabhängig ist.

Die werterhaltender Ansatz Aufrufe zum Heraufstufen dieser Typen zu signed int, wenn dieser Typ alle Werte des ursprünglichen Typs richtig darstellen kann, und andernfalls zum Heraufstufen dieser Typen zu unsigned int. Wenn also die Ausführungsumgebung short als etwas Kleineres als int darstellt, wird unsigned short zu int; andernfalls wird es unsigned int.

Dies kann in einigen Fällen zu ziemlich unerwarteten Ergebnissen führen, da das inkonsistente Verhalten der impliziten Konvertierung zwischen vorzeichenlosen und größeren vorzeichenbehafteten Typen demonstriert, es gibt viele weitere Beispiele dafür. Obwohl dies in den meisten Fällen dazu führt, dass die Vorgänge wie erwartet funktionieren.

  • Ja, manchmal wird es kleiner und schneller, weil Sie keine zusätzlichen Anweisungen benötigen, um die Werte auf int zu erweitern oder die hohen Bits zu maskieren. In x86 benötigen Sie auch keine zusätzlichen Anweisungspräfixe, um die Argumentgröße zu ändern

    – phuklv

    24. Juni 2014 um 2:46 Uhr

  • Schade, dass die Begründung keine sekundäre Regel hinzugefügt hat, dass, wenn das Ergebnis eines additiven, multiplikativen oder bitweisen Operators auf einen vorzeichenlosen Typ kleiner als gezwungen wird int, verhält sich der Ausdruck so, als wären seine Operanden ebenfalls erzwungen und die Operation auf dem kleineren Typ ausgeführt worden. Es gibt keine definierten Fälle, die einer solchen Regel widersprechen würden, aber einige Compiler verwenden möglicherweise eine Heraufstufung als Entschuldigung, um darauf zu schließen, dass eine Aussage like like ist x*=y; (mit beiden Variablen unsigned short) verspricht das x darf 2147483648/Jahr nicht überschreiten.

    – Superkatze

    12. September 2015 um 18:11 Uhr


  • wenn ich sowas habe int x = 1234 und char *y = &x . Binäre Darstellung von 1234 ist 00000000 00000000 00000100 11010010 . Meine Maschine ist Little Endian, also kehrt sie sie um und speichert sie im Speicher 11010010 00000100 00000000 00000000 LSB kommt zuerst. Jetzt Hauptteil. wenn ich benutze printf("%d" , *p). printf wird das erste Byte lesen 11010010nur die Ausgabe ist -46 aber 11010010 ist 210 also warum druckt es -46 . Ich bin wirklich verwirrt, ich schätze, einige Char-to-Integer-Promotion macht etwas, aber ich weiß es nicht.

    – Suraj Jain

    17. August 2016 um 10:24 Uhr

  • Sie zitieren den C99-Standard, aber ist dieses Verhalten nicht älter? Ich muss ins Bett, o/w Ich würde sehen, ob ich etwas in K&R finden könnte.

    – PJTrail

    9. März 2017 um 23:39 Uhr

  • @PJTrail gut Wikipedia zeigen Sie auf eine Version von c89 obwohl Sie keinen offiziellen Entwurf bekommen können. In dieser Version unter Übliche arithmetische Umrechnungen es beschreibt ein sehr ähnliches Verfahren. Also ich würde ja sagen. Beachten Sie das Zitat oben sagt leichte Modifikationen von denen in K&R K&R sollte also anders sein.

    – Shafik Yaghmour

    10. März 2017 um 4:46 Uhr

1647092413 590 Warum muss in C und C vor arithmetischen Operationen ein
Phonon

Es ist weniger ein Merkmal der Sprache als vielmehr eine Einschränkung der physischen Prozessorarchitekturen, auf denen der Code ausgeführt wird. Die int Typer in C hat normalerweise die Größe Ihres Standard-CPU-Registers. Mehr Silizium nimmt mehr Platz und mehr Leistung ein, sodass in vielen Fällen Arithmetik nur mit den Datentypen „natürlicher Größe“ durchgeführt werden kann. Dies trifft nicht allgemein zu, aber die meisten Architekturen haben immer noch diese Einschränkung. Mit anderen Worten, wenn zwei 8-Bit-Zahlen addiert werden, ist das, was tatsächlich im Prozessor vor sich geht, eine Art 32-Bit-Arithmetik, gefolgt von entweder einer einfachen Bitmaske oder einer anderen geeigneten Typumwandlung.

  • Ich bin mir nicht sicher, ob es unbedingt eine kleine Maske gibt. Der Prozessor führt die Arithmetik in seiner nativen Wortgröße durch und speichert dann nur die unteren Bits zurück in den Speicher. (Obwohl Sie Recht haben, dass die meisten Architekturen nur Wortarithmetik ausführen, ist die einzige bemerkenswerte Ausnahme, Intel, ziemlich weit verbreitet.)

    – James Kanze

    23. Juni 2014 um 19:00 Uhr

  • @JamesKanze Du hast Recht. Ich habe per Antwort bearbeitet. Und ja, Intel ist weit draußen, wenn es um optimierte Arithmetik geht, insbesondere mit ihren IPP-Bibliotheken.

    – Phonon

    23. Juni 2014 um 19:04 Uhr

  • Ich bin nicht einverstanden mit “es ist kein Merkmal der Sprache”; es ist ein Merkmal der Sprache. Es ist so definiert, weil … aber es wird durch die Sprache definiert, nicht durch den Prozessor.

    – Jonathan Leffler

    23. Juni 2014 um 23:55 Uhr

  • @JonathanLeffler Es ist sicherlich ein Merkmal der Sprache. Von den meisten Sprachen, denke ich. Aber Phonons Antwort erklärt es warum Sprachen haben diese Funktion. (Es ist wahrscheinlich erwähnenswert, dass Maschinen in der Vergangenheit nur Wörter hatten, keine Bytes, Halbwörter usw. Und als die Byte-Adressierung eingeführt wurde, betraf sie nur den Speicherzugriff, nicht Register und Operationen. Während der PDP-11 hatte sowohl Byte- als auch Wortbefehle, wenn die Zieladresse eines Bytebefehls ein Register war, wurde das Byte vorzeichenerweitert zu einem Wort.)

    – James Kanze

    24. Juni 2014 um 7:58 Uhr

  • Wie die CPU Befehle ausführt, ist dem Benutzercode vollständig verborgen. Sie haben die Frage überhaupt nicht beantwortet.

    – Sophit

    24. Juni 2014 um 20:37 Uhr

1647092413 952 Warum muss in C und C vor arithmetischen Operationen ein
6502

short und char Typen werden von der Standardart “Speichertypen” betrachtet, dh Teilbereiche, die Sie verwenden können, um etwas Platz zu sparen, die Ihnen jedoch keine Geschwindigkeit verschaffen, da ihre Größe für die CPU “unnatürlich” ist.

Auf bestimmten CPUs ist dies nicht wahr, aber gute Compiler sind schlau genug zu bemerken, dass, wenn Sie zB eine Konstante zu einem unsigned char hinzufügen und das Ergebnis wieder in einem unsigned char speichern, es nicht nötig ist, durch die zu gehen unsigned char -> int Wandlung. Beispielsweise wird mit g++ der Code für die innere Schleife von generiert

void incbuf(unsigned char *buf, int size) {
    for (int i=0; i<size; i++) {
        buf[i] = buf[i] + 1;
    }
}

ist nur

.L3:
    addb    $1, (%rdi,%rax)
    addq    $1, %rax
    cmpl    %eax, %esi
    jg  .L3
.L1:

wo Sie sehen können, dass eine unsignierte Zeichenadditionsanweisung (addb) wird genutzt.

Dasselbe passiert, wenn Sie Ihre Berechnungen zwischen short ints durchführen und das Ergebnis in short ints speichern.

1647092413 601 Warum muss in C und C vor arithmetischen Operationen ein
ssube

Die verknüpfte Frage scheint es ziemlich gut abzudecken: Die CPU tut es einfach nicht. Eine 32-Bit-CPU hat ihre nativen arithmetischen Operationen für 32-Bit-Register eingerichtet. Der Prozessor arbeitet lieber in seiner bevorzugten Größe, und für Operationen wie diese ist es billig, einen kleinen Wert in ein Register mit nativer Größe zu kopieren. (Bei der x86-Architektur werden die 32-Bit-Register so benannt, als wären sie erweiterte Versionen der 16-Bit-Register (eax zu ax, ebx zu bx, etc); sehen x86-Integer-Anweisungen).

Für einige sehr häufige Operationen, insbesondere Vektor-/Float-Arithmetik, kann es spezielle Anweisungen geben, die mit einem anderen Registertyp oder einer anderen Registergröße arbeiten. Für so etwas wie ein kurzes Auffüllen mit (bis zu) 16 Bits Nullen hat es sehr geringe Leistungskosten und das Hinzufügen spezialisierter Anweisungen ist wahrscheinlich nicht die Zeit oder den Platz auf dem Würfel wert (wenn Sie wirklich wissen wollen, warum; ich bin Ich bin mir nicht sicher, ob sie tatsächlich Platz einnehmen würden, aber es wird viel komplexer).

993750cookie-checkWarum muss in C und C++ vor arithmetischen Operationen ein short in ein int umgewandelt werden?

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

Privacy policy