Weil, obwohl a
und b
jeweils vom Typ char
sind, der Ausdruck a + b
vom Typ int
ist. Immer wenn Sie math mit char-Typen machen, werden sie vor den eigentlichen Berechnungen in int konvertiert.
Wenn Sie sich die ANSI C-Spezifikation ansehen, hier , werden die addierten Ausdrücke analysiert.
Mehr darüber, wie dies geparst wird und wie Operanden gelesen werden:
Der Integraloperand eines additiven Operators, der einen Zeiger und eine Ganzzahl enthält, wird als TypeIs_unsigned_long angegeben. Jeder Integraltyp kann mithilfe impliziter Konvertierungen in TypeIs_unsigned_long konvertiert werden, sodass diese Spezifikation der des Standards entspricht. Der Hauptgrund für die Verwendung von TypeIs_unsigned_long ist, dass OIL keine Mengen als Operandenspezifikationen innerhalb einer Klassendefinition zulässt, aber ein zweiter Grund ist, dass dieser Ansatz die Gesamtzahl der Operatoren in der Compiler-Datenbank reduziert.
1) Dies druckt nur die Textzeichenfolge "etwas + etwas anderes" aus: Sie fügen nichts hinzu: printf("%d + %d = %d\n",..)
2) sizeof(<some char>)
wird immer "1" sein. Das ist, was "sizeof ()" bedeutet - es kann niemals etwas neben "1" sein.
3) Ja, das Hinzufügen von "char" (was ein ganzzahliger Untertyp ist) ergibt ein ganzzahliges Ergebnis.
Für weitere Details:
Der Typ char, die Ganzzahlarten mit und ohne Vorzeichen und der Aufzählungstypen werden zusammen als Integertypen bezeichnet. Die Ganzzahl und echte schwebende Typen werden zusammen als reale Typen bezeichnet.
Wenn das Ergebnis nicht hochgestuft wird, kann es überlaufen.
Ein einzelnes Byte-Zeichen kann keinen Wert größer als 255 (unsigned) oder +127 (signed) enthalten. Wenn Sie zwei Instanzen summieren, gibt es immer die Möglichkeit eines Überlaufs, d. H. Ein Ergebnis größer als 255. Dies bedeutet, dass es nicht in einem einzelnen Byte gespeichert werden kann. Daher wird int verwendet, das die maximale Summe von zwei Zeichen oder Bytes nicht überschreiten kann.
Abschnitt 4.5 Integrale Werbung
Ein Pr-Wert eines anderen Integer-Typs als bool, char16_t, char32_t oder wchar_t, dessen Ganzzahlumwandlungsrang (4.13) kleiner ist als der Rang von int kann in einen prvalue vom Typ int konvertiert werden, wenn int alle darstellen kann die Werte des Quelltyps; Andernfalls kann der Quellprwert sein konvertiert in einen prvalue vom Typ unsigned int.
Die Umwandlung wird vom Standard in dem sogenannten "Die üblichen arithmetischen Umwandlungen" Klausel 5 [expr] Punkt 10:
vorgeschriebenViele binäre Operatoren, die Operanden der Arithmetik oder erwarten Aufzählungstyp verursacht Konvertierungen und liefert Ergebnistypen in a ähnlich Viele binäre Operatoren, die Operanden der Arithmetik oder Aufzählungstyp verursacht Konvertierungen und Ergebnistypen ähnlich Weg. Der Zweck ist es, einen gemeinsamen Typ zu ergeben, der auch die Art von ist das Ergebnis. Dieses Muster wird die üblichen arithmetischen Umwandlungen genannt, die wie folgt definiert sind: Weg. Der Zweck ist es, ein gemeinsames zu ergeben Typ, der auch der Typ des Ergebnisses ist. Dieses Muster nennt man übliche arithmetische Konvertierungen, die wie folgt definiert sind:
Außer für einige ausgewählte Typen. long double, double
und float
Andernfalls müssen die integralen Beförderungen (4.5) für beide durchgeführt werden Operanden.59
Das (char) + (char) führt zu einem int.
Beachten Sie auch, dass ein char + char knifflig ist. Das Zeichen kann je nach Implementierung signiert oder vorzeichenlos sein; Daher kann das Ergebnis leicht für normale Werte überlaufen, was wahrscheinlich ist, warum es als Ausnahme nicht im Standard enthalten ist.
So arbeiten C und C ++: Bevor sie etwas an Variablen vom Typ char
vornehmen, konvertiert der Compiler sie in int
zuerst. Dies wird als Integer-Promotion bezeichnet. Hinweis: alles ist durch die C- und C ++ - Standards definiert. Es enthält nicht sizeof
, sondern enthält die meisten anderen Operationen (ich kann mich an keine Ausnahmen neben der sizeof
Eins erinnern).
Was den Grund für dieses vielleicht überraschende Verhalten angeht - dies ist wahrscheinlich eine Entscheidung aus der Antike, die dazu führte, dass sich modernes C und C ++ seither so verhalten, um Kompatibilität zu erreichen.
Leute hatten oft große Arrays von char
s, die nicht wirklich Zeichen, sondern kleine Zahlen waren. Bei der Arithmetik mit diesen war es natürlich, jede Zahl automatisch in int
umzuwandeln und arithmetisch zu arbeiten, weil int
der Typ ist, für den die Arithmetik am schnellsten arbeitet. Es gibt auch den angenehmen Nebeneffekt, dass ein Überlauf viel weniger wahrscheinlich ist, wenn der Aufstieg in Kraft ist (beachte a*b
, wenn a
und b
vom char
-Typ sind).
Darüber hinaus setzt printf
auf Ganzzahl-Hochstufung, um ASCII-Werte für Zeichen zu drucken: printf("%d", a)
erwartet, dass der Parameter char
-typed in int
hochgestuft wird, wenn printf
aufgerufen wird.
Der Grund für diese Werbung ist historisch: Als C vor 40 Jahren erfunden wurde, haben Prozessoren Mathe an einem einzigen ganzzahligen Typ gemacht; Sie könnten kleinere Typen speichern, aber es gab keine Arithmetik auf Byte-Ebene. Die Promotion-Regel spiegelt also die Realität zu der Zeit wider: Typen, die kleiner als der Integer-Typ des Prozessors sind, würden von der Hardware auf diesen Integer-Typ hochgestuft. Sicher, Sie könnten die Mathematik in Software tun (wie long
wurde oft implementiert), aber das wäre viel langsamer gewesen (wie long
oft war).