Aus den Antworten, die ich aus dieser Frage erhalten habe , geht hervor, dass C ++ diese Anforderung für die Konvertierung short
in int
bei der Ausführung von arithmetischen Operationen von C geerbt hat . Darf ich Ihnen überlegen, warum dies überhaupt in C eingeführt wurde? Warum nicht einfach diese Operationen als short
?
Zum Beispiel ( entnommen aus dem Vorschlag von dyp in den Kommentaren ):
short s = 1, t = 2 ;
auto x = s + t ;
x
wird Typ von int haben .
short s=1, t=2; auto x = s+t;
dannx
ist einint
.int
nicht befördert wirdlong
(maxint + maxint> maxint).x
ist der Typint
sind völlig verschieden in C und C ++ , obwohl ... ;-)Antworten:
Wenn wir uns die Gründe für den internationalen Standard - Programmiersprachen - C im Abschnitt
6.3.1.8
Übliche arithmetische Konvertierungen ansehen , heißt es ( Hervorhebung meiner in Zukunft ):Abschnitt 6.3.1.8 des Entwurfs der C99-Norm behandelt die üblichen arithmetischen Konvertierungen, die auf Operanden arithmetischer Ausdrücke angewendet werden, z. B. Abschnitt 6.5.6 Additive Operatoren lautet:
Einen ähnlichen Text finden wir auch in Abschnitt 6.5.5 Multiplikative Operatoren . Im Fall eines kurzen Operanden werden zuerst die Ganzzahl- Heraufstufungen aus Abschnitt 6.3.1.1 Boolescher Wert, Zeichen und Ganzzahlen angewendet , der besagt:
Die Diskussion aus dem Abschnitt
6.3.1.1
der Begründung oder des internationalen Standards - Programmiersprachen - C über ganzzahlige Beförderungen ist tatsächlich interessanter. Ich werde b / c selektiv zitieren. Es ist zu lang, um sie vollständig zu zitieren:Dies kann in einigen Fällen zu unerwarteten Ergebnissen führen, wie das inkonsistente Verhalten der impliziten Konvertierung zwischen vorzeichenlosen und größeren vorzeichenbehafteten Typen zeigt. Es gibt noch viele weitere Beispiele dafür. Obwohl dies in den meisten Fällen dazu führt, dass die Vorgänge wie erwartet funktionieren.
quelle
int
, verhält sich der Ausdruck so, als ob seine Operanden ebenfalls erzwungen und die Operation für den ausgeführt würden kleinerer Typ. Es gibt keine definierten Fälle, die einer solchen Regel widersprechen würden, aber einige Compiler verwenden möglicherweise die Werbung als Ausrede, um daraus zu schließen, dass eine Aussage wie likex*=y;
(mit beiden Variablenunsigned short
) verspricht,x
2147483648 / y nicht zu überschreiten.int x = 1234
undchar *y = &x
. Binäre Darstellung von1234
ist00000000 00000000 00000100 11010010
. Meine Maschine ist Little Endian, also kehrt sie es um und das Speichern im Speicher11010010 00000100 00000000 00000000
LSB steht an erster Stelle. Jetzt Hauptteil. wenn ich benutzeprintf("%d" , *p)
.printf
lesen werden erste Byte ist11010010
der Ausgang nur ,-46
sondern11010010
ist210
so , warum gedruckt wird es-46
. Ich bin wirklich verwirrt, ich denke, ein Zeichen für eine ganzzahlige Werbung macht etwas, aber ich weiß es nicht.Dies ist weniger ein Merkmal der Sprache als vielmehr eine Einschränkung der physischen Prozessorarchitekturen, auf denen der Code ausgeführt wird. Der
int
Typer in C entspricht normalerweise der Größe Ihres Standard-CPU-Registers. Mehr Silizium nimmt mehr Platz und mehr Leistung in Anspruch, sodass in vielen Fällen nur mit den Datentypen "natürliche Größe" gerechnet werden kann. Dies ist nicht allgemein gültig, aber die meisten Architekturen haben immer noch diese Einschränkung. Mit anderen Worten, wenn zwei 8-Bit-Zahlen hinzugefügt werden, geschieht im Prozessor tatsächlich eine Art 32-Bit-Arithmetik, gefolgt von einer einfachen Bitmaske oder einer anderen geeigneten Typkonvertierung.quelle
short
undchar
Typen werden von der Standardart "Speichertypen" berücksichtigt, dh Unterbereiche, mit denen Sie Platz sparen können, die Ihnen jedoch keine Geschwindigkeit verschaffen, da ihre Größe für die CPU "unnatürlich" ist.Auf bestimmten CPUs ist dies nicht der Fall, aber gute Compiler sind klug genug zu bemerken, dass Sie die
unsigned char -> int
Konvertierung nicht durchführen müssen, wenn Sie beispielsweise einem vorzeichenlosen Zeichen eine Konstante hinzufügen und das Ergebnis in einem vorzeichenlosen Zeichen speichern . Zum Beispiel mit g ++ der Code, der für die innere Schleife von generiert wurdevoid incbuf(unsigned char *buf, int size) { for (int i=0; i<size; i++) { buf[i] = buf[i] + 1; } }
ist nur
Hier sehen Sie, dass eine vorzeichenlose Anweisung zum Hinzufügen von Zeichen (
addb
) verwendet wird.Das gleiche passiert, wenn Sie Ihre Berechnungen zwischen kurzen Ints durchführen und das Ergebnis in kurzen Ints speichern.
quelle
Die verknüpfte Frage scheint es ziemlich gut abzudecken: Die CPU tut es einfach nicht. Bei einer 32-Bit-CPU sind die 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 das Kopieren eines kleinen Werts in ein Register mit nativer Größe billig. (Für die x86-Architektur werden die 32-Bit-Register so benannt, als wären sie erweiterte Versionen der 16-Bit-Register (
eax
toax
,ebx
tobx
usw.); siehe x86-Integer-Anweisungen ).Für einige extrem gebräuchliche Operationen, insbesondere Vektor / Float-Arithmetik, kann es spezielle Anweisungen geben, die mit einem anderen Registertyp oder einer anderen Registegröße arbeiten. Für so etwas wie eine kurze Zeit hat das Auffüllen mit (bis zu) 16 Bit Nullen nur sehr geringe Leistungskosten, und das Hinzufügen spezieller Anweisungen ist wahrscheinlich weder Zeit noch Platz auf dem Würfel wert (wenn Sie wirklich physisch wissen möchten, warum; ich bin es Ich bin mir nicht sicher, ob sie tatsächlich Platz beanspruchen würden, aber es wird viel komplexer.
quelle