Namespaces
Variants

Arithmetic operators

From cppreference.net

Arithmetische Operatoren wenden Standardmathematische Operationen auf ihre Operanden an.

Operator Operatorname Beispiel Ergebnis
+ Unäres Plus + a Der Wert von a nach Typenerweiterungen
- Unäres Minus - a Das Negative von a
+ Addition a + b Die Addition von a und b
- Subtraktion a - b Die Subtraktion von b von a
* Produkt a * b Das Produkt von a und b
/ Division a / b Die Division von a durch b
% Rest a % b Der Rest der Division von a durch b
~ Bitweises NOT ~a Das bitweise NOT von a
& Bitweises AND a & b Das bitweise AND von a und b
| Bitweises OR a | b Das bitweise OR von a und b
^ Bitweises XOR a ^ b Das bitweise XOR von a und b
<< Bitweise Linksverschiebung a << b a links verschoben um b
>> Bitweise Rechtsverschiebung a >> b a rechts verschoben um b

Inhaltsverzeichnis

Überläufe

Die Arithmetik vorzeichenloser Ganzzahlen wird immer modulo 2 n
durchgeführt, wobei n die Anzahl der Bits in dieser bestimmten Ganzzahl ist. Zum Beispiel ergibt für unsigned int das Addieren von eins zu UINT_MAX den Wert 0 , und das Subtrahieren von eins von 0 ergibt UINT_MAX .

Wenn eine Operation mit vorzeichenbehafteten Ganzzahlen überläuft (das Ergebnis passt nicht in den Ergebnistyp), ist das Verhalten undefiniert: Es kann gemäß den Regeln der Darstellung umschlagen (typischerweise 2er-Komplement), es kann auf einigen Plattformen oder aufgrund von Compiler-Optionen zu einem Trap führen (z.B. -ftrapv in GCC und Clang), oder es kann vom Compiler vollständig optimiert werden .

Gleitkomma-Umgebung

Wenn #pragma STDC FENV_ACCESS auf ON gesetzt ist, befolgen alle Gleitkomma-Operatoren die aktuelle Rundungsrichtung und melden Gleitkomma-Arithmetikfehler wie in math_errhandling spezifiziert, es sei denn, sie sind Teil einer statischen Initialisierung (in diesem Fall werden keine Gleitkomma-Ausnahmen ausgelöst und der Rundungsmodus ist "to nearest").

Gleitkomma-Kontraktion

Sofern #pragma STDC FP_CONTRACT nicht auf OFF gesetzt ist, darf jede Gleitkomma-Operation so ausgeführt werden, als hätten die Zwischenergebnisse unendlichen Wertebereich und unendliche Genauigkeit, d.h. Optimierungen, die Rundungsfehler und Gleitkomma-Ausnahmen unterdrücken, die beobachtet würden, wenn der Ausdruck exakt wie geschrieben ausgewertet würde. Erlaubt beispielsweise die Implementierung von ( x * y ) + z mit einer einzigen Fused-Multiply-Add-CPU-Instruktion oder die Optimierung von a = x * x * x * x ; zu tmp = x * x ; a = tmp * tmp .

Unabhängig von der Vertragsgestaltung können Zwischenergebnisse der Gleitkommaarithmetik einen Bereich und eine Genauigkeit aufweisen, die von der durch ihren Typ angegebenen abweichen, siehe FLT_EVAL_METHOD

Unäre Arithmetik

Die unären arithmetischen Operatorausdrücke haben die Form

+ Ausdruck (1)
- Ausdruck (2)
1) unärer Plus-Operator (Promotion)
2) unärer Minusoperator (Negation)
expression - Ausdruck eines beliebigen arithmetic type

Sowohl unäres Plus als auch unäres Minus wenden zuerst integral promotions auf ihren Operanden an und dann

  • Unärer Plus-Operator gibt den Wert nach Promotion zurück
  • Unärer Minus-Operator gibt den negativen Wert nach Promotion zurück (außer dass das Negative eines NaN ein weiteres NaN ist)

Der Typ des Ausdrucks ist der Typ nach der Höherstufung, und die value category ist non-lvalue.

Hinweise

Der unäre Minus-Operator ruft undefiniertes Verhalten aufgrund von vorzeichenbehaftetem Ganzzahlüberlauf auf, wenn er auf INT_MIN , LONG_MIN oder LLONG_MIN auf typischen (2er-Komplement) Plattformen angewendet wird.

In C++ kann der unäre Operator + auch mit anderen eingebauten Typen wie Arrays und Funktionen verwendet werden, was in C nicht der Fall ist.

#include <stdio.h>
#include <complex.h>
#include <limits.h>
int main(void)
{
    char c = 'a';
    printf("sizeof char: %zu sizeof int: %zu\n", sizeof c, sizeof +c);
    printf("-1, where 1 is signed: %d\n", -1);
    // Definierte Ausführung, da Arithmetik für vorzeichenlose Ganzzahlen durchgeführt wird.
    // Daher ist die Berechnung (-1) modulo (2 hoch n) = UINT_MAX, wobei n
    // die Anzahl der Bits von unsigned int ist. Wenn unsigned int 32 Bit lang ist, dann ergibt dies
    // (-1) modulo (2 hoch 32) = 4294967295
    printf("-1, where 1 is unsigned: %u\n", -1u); 
    // Undefiniertes Verhalten, weil der mathematische Wert von -INT_MIN = INT_MAX + 1
    // (d.h. 1 mehr als der maximal mögliche Wert für signed int)
    //
    // printf("%d\n", -INT_MIN);
    // Undefiniertes Verhalten, weil der mathematische Wert von -LONG_MIN = LONG_MAX + 1
    // (d.h. 1 mehr als der maximal mögliche Wert für signed long)
    //
    // printf("%ld\n", -LONG_MIN);
    // Undefiniertes Verhalten, weil der mathematische Wert von -LLONG_MIN = LLONG_MAX + 1
    // (d.h. 1 mehr als der maximal mögliche Wert für signed long long)
    //
    // printf("%lld\n", -LLONG_MIN);
    double complex z = 1 + 2*I;
    printf("-(1+2i) = %.1f%+.1f\n", creal(-z), cimag(-z));
}

Mögliche Ausgabe:

sizeof char: 1 sizeof int: 4
-1, where 1 is signed: -1
-1, where 1 is unsigned: 4294967295
-(1+2i) = -1.0-2.0

Additive Operatoren

Die binären additiven arithmetischen Operatorausdrücke haben die Form

lhs + rhs (1)
lhs - rhs (2)
1) Addition: lhs und rhs müssen eines der folgenden sein
  • beide haben arithmetic types , einschließlich komplexer und imaginärer
  • einer ist ein Zeiger auf einen vollständigen Objekttyp, der andere hat ganzzahligen Typ
2) Subtraktion: lhs und rhs müssen einem der folgenden Fälle entsprechen
  • beide haben arithmetische Typen , inklusive komplexe und imaginäre
  • lhs hat Zeiger auf vollständigen Objekttyp, rhs hat ganzzahligen Typ
  • beide sind Zeiger auf vollständige Objekte mit kompatiblen Typen, unter Ignorierung von Qualifizierern

Arithmetische Addition und Subtraktion

Wenn beide Operanden arithmetische Typen haben, dann

  • zuerst werden usual arithmetic conversions durchgeführt
  • dann werden die Werte der Operanden nach den Konvertierungen gemäß den üblichen mathematischen Regeln addiert oder subtrahiert (bei Subtraktion wird rhs von lhs subtrahiert), mit der Ausnahme, dass
  • wenn ein Operand NaN ist, ist das Ergebnis NaN
  • Unendlich minus Unendlich ist NaN und FE_INVALID wird ausgelöst
  • Unendlich plus negativ Unendlich ist NaN und FE_INVALID wird ausgelöst

Komplexe und imaginäre Addition und Subtraktion sind wie folgt definiert (beachten Sie, dass der Ergebnistyp imaginär ist, wenn beide Operanden imaginär sind, und komplex, wenn ein Operand reell und der andere imaginär ist, wie durch die üblichen arithmetischen Konvertierungen festgelegt):

+ oder - u iv u + iv
x x ± u x ± iv (x ± u) ± iv
iy ±u + iy i(y ± v) ±u + i(y ± v)
x + iy (x ± u) + iy x + i(y ± v) (x ± u) + i(y ± v)


// work in progress
// note: take part of the c/language/conversion example

Zeigerarithmetik

  • Wenn der Zeiger P auf ein Element eines Arrays mit Index I zeigt, dann
  • P + N und N + P sind Zeiger, die auf ein Element desselben Arrays mit Index I+N zeigen
  • P - N ist ein Zeiger, der auf ein Element desselben Arrays mit Index I-N zeigt

Das Verhalten ist nur definiert, wenn sowohl der ursprüngliche Zeiger als auch der resultierende Zeiger auf Elemente desselben Arrays oder auf das Element nach dem Ende des Arrays zeigen. Beachten Sie, dass die Ausführung von p-1, wenn p auf das erste Element eines Arrays zeigt, undefiniertes Verhalten ist und auf einigen Plattformen fehlschlagen kann.

  • Wenn der Zeiger P1 auf ein Element eines Arrays mit Index I (oder eins hinter dem Ende) zeigt und P2 auf ein Element desselben Arrays mit Index J (oder eins hinter dem Ende) zeigt, dann
  • P1 - P2 hat den Wert gleich I - J und den Typ ptrdiff_t (was ein vorzeichenbehafteter Ganzzahltyp ist, typischerweise halb so groß wie die Größe des größten Objekts, das deklariert werden kann)

Das Verhalten ist nur definiert, wenn das Ergebnis in ptrdiff_t passt.

Für den Zweck der Zeigerarithmetik wird ein Zeiger auf ein Objekt, das kein Element eines Arrays ist, als Zeiger auf das erste Element eines Arrays der Größe 1 behandelt.

// work in progress
int n = 4, m = 3;
int a[n][m];     // VLA of 4 VLAs of 3 ints each
int (*p)[m] = a; // p == &a[0] 
p = p + 1;       // p == &a[1] (pointer arithmetic works with VLAs just the same)
(*p)[2] = 99;    // changes a[1][2]

Multiplikative Operatoren

Die binären multiplikativen arithmetischen Operatorausdrücke haben die Form

lhs * rhs (1)
lhs / rhs (2)
lhs % rhs (3)
1) Multiplikation. lhs und rhs müssen arithmetische Typen haben
2) Division. lhs und rhs müssen arithmetische Typen haben
3) Rest. lhs und rhs müssen Ganzzahltypen haben

Multiplikation

Der binäre Operator * führt eine Multiplikation seiner Operanden durch (nach üblichen arithmetischen Konvertierungen) gemäß den üblichen arithmetischen Definitionen, außer dass

  • wenn ein Operand ein NaN ist, ist das Ergebnis ein NaN
  • Multiplikation von Unendlich mit Null ergibt NaN und FE_INVALID wird ausgelöst
  • Multiplikation von Unendlich mit einem Wert ungleich Null ergibt Unendlich (selbst für komplexe Argumente)

Da in C jeder komplexe Wert mit mindestens einem unendlichen Anteil als Unendlichkeit gilt, selbst wenn sein anderer Anteil ein NaN ist, gelten die üblichen arithmetischen Regeln nicht für komplex-komplexe Multiplikation. Andere Kombinationen von Gleitkommaoperanden folgen der folgenden Tabelle:

* u iv u + iv
x xu i(xv) (xu) + i(xv)
iy i(yu) −yv (−yv) + i(yu)
x + iy (xu) + i(yu) (−yv) + i(xv) spezielle Regeln

Neben der Behandlung von Unendlichkeiten ist es bei der komplexen Multiplikation nicht erlaubt, dass Zwischenergebnisse überlaufen, es sei denn, #pragma STDC CX_LIMITED_RANGE ist auf ON gesetzt, in welchem Fall der Wert berechnet werden darf, als ob durch (x+iy)×(u+iv) = (xu-yv)+i(yu+xv) , da der Programmierer die Verantwortung übernimmt, den Bereich der Operanden zu begrenzen und mit den Unendlichkeiten umzugehen.

Trotz des Verbots von unzulässigem Überlauf kann die komplexe Multiplikation unzugehörige Gleitkomma-Ausnahmen auslösen (ansonsten ist es unvertretbar schwierig, nicht-überlaufende Versionen zu implementieren)

#include <stdio.h>
#include <stdio.h>
#include <complex.h>
#include <math.h>
int main(void)
{
// TODO einfachere Fälle, einige aus C++ übernehmen
   double complex z = (1 + 0*I) * (INFINITY + I*INFINITY);
// Lehrbuchformel würde ergeben
// (1+i0)(∞+i∞) ⇒ (1×∞ – 0×∞) + i(0×∞+1×∞) ⇒ NaN + I*NaN
// aber C liefert eine komplexe Unendlichkeit
   printf("%f + i*%f\n", creal(z), cimag(z));
// Lehrbuchformel würde ergeben
// cexp(∞+iNaN) ⇒ exp(∞)×(cis(NaN)) ⇒ NaN + I*NaN
// aber C liefert ±∞+i*nan
   double complex y = cexp(INFINITY + I*NAN);
   printf("%f + i*%f\n", creal(y), cimag(y));
}

Mögliche Ausgabe:

inf + i*inf 
inf + i*nan

Division

Der binäre Operator / dividiert den ersten Operanden durch den zweiten (nach üblichen arithmetischen Konvertierungen) gemäß den üblichen arithmetischen Definitionen, außer dass

  • wenn der Typ nach den üblichen arithmetischen Konvertierungen ein Ganzzahltyp ist, ist das Ergebnis der algebraische Quotient (kein Bruch), gerundet in implementierungsdefinierter Richtung (bis C99) abgeschnitten in Richtung Null (seit C99)
  • wenn ein Operand ein NaN ist, ist das Ergebnis ein NaN
  • wenn der erste Operand eine komplexe Unendlichkeit ist und der zweite Operand endlich ist, dann ist das Ergebnis des / Operators eine komplexe Unendlichkeit
  • wenn der erste Operand endlich ist und der zweite Operand eine komplexe Unendlichkeit ist, dann ist das Ergebnis des / Operators eine Null.

Weil in C jeder komplexe Wert mit mindestens einem unendlichen Anteil als Unendlichkeit gilt, selbst wenn sein anderer Anteil ein NaN ist, gelten die üblichen arithmetischen Regeln nicht für die komplex-komplex Division. Andere Kombinationen von Fließkomma-Operanden folgen der folgenden Tabelle:

/ u iv
x x/u i(−x/v)
iy i(y/u) y/v
x + iy (x/u) + i(y/u) (y/v) + i(−x/v)

Neben der Behandlung von Unendlichkeiten ist es bei der komplexen Division nicht erlaubt, dass Zwischenergebnisse überlaufen, es sei denn, #pragma STDC CX_LIMITED_RANGE ist auf ON gesetzt, in welchem Fall der Wert berechnet werden darf, als ob durch (x+iy)/(u+iv) = [(xu+yv)+i(yu-xv)]/(u 2
+v 2
)
, da der Programmierer die Verantwortung übernimmt, den Bereich der Operanden zu begrenzen und mit den Unendlichkeiten umzugehen.

Trotz der Unterbindung unzulässigen Überlaufs kann die komplexe Division möglicherweise unbegründete Gleitkomma-Ausnahmen auslösen (ansonsten ist es unvertretbar schwierig, nicht-überlaufende Versionen zu implementieren)

Wenn der zweite Operand null ist, ist das Verhalten undefiniert, außer wenn IEEE-Gleitkommaarithmetik unterstützt wird und eine Gleitkommadivision stattfindet, dann

  • Die Division einer Zahl ungleich Null durch ±0,0 ergibt das korrekt vorzeichenbehaftete Unendlich und FE_DIVBYZERO wird ausgelöst
  • Die Division von 0,0 durch 0,0 ergibt NaN und FE_INVALID wird ausgelöst

Rest

Der binäre Operator % liefert den Rest der Division des ersten Operanden durch den zweiten (nach üblichen arithmetischen Umwandlungen).

Das Vorzeichen des Rests ist so definiert, dass, wenn der Quotient a/b im Ergebnistyp darstellbar ist, dann ( a / b ) * b + a % b == a .

Wenn der zweite Operand null ist, ist das Verhalten undefiniert.

Wenn der Quotient a/b im Ergebnistyp nicht darstellbar ist, ist das Verhalten von sowohl a/b als auch a%b undefiniert (das bedeutet INT_MIN %- 1 ist auf 2er-Komplement-Systemen undefiniert)

Hinweis: Der Restoperator funktioniert nicht mit Gleitkommatypen, die Bibliotheksfunktion fmod bietet diese Funktionalität.

Bitweise Logik

Die bitweisen arithmetischen Operatorausdrücke haben die Form

~ rhs (1)
lhs & rhs (2)
lhs | rhs (3)
lhs ^ rhs (4)
1) bitweise NOT
2) bitweise UND-Operation
3) bitweises ODER
4) bitweise XOR

wobei

lhs , rhs - Ausdrücke ganzzahligen Typs

Zunächst führen die Operatoren & , ^ und | übliche arithmetische Konvertierungen auf beiden Operanden durch, und der Operator ~ führt Integer-Promotions auf seinem einzigen Operanden durch.

Dann werden die entsprechenden binären Logikoperatoren bitweise angewendet; das heißt, jedes Bit des Ergebnisses wird gesetzt oder gelöscht gemäß der Logikoperation (NOT, AND, OR oder XOR), angewendet auf die entsprechenden Bits der Operanden.

Hinweis: Bitweise Operatoren werden häufig zur Manipulation von Bit-Sets und Bit-Masken verwendet.

Hinweis: Für vorzeichenlose Typen (nach Höherstufung) ist der Ausdruck ~E äquivalent zum maximalen darstellbaren Wert des Ergebnistyps minus dem ursprünglichen Wert von E .

#include <stdio.h>
#include <stdint.h>
int main(void)
{
    uint32_t a = 0x12345678;
    uint16_t mask = 0x00f0;
    printf("Promoted mask:\t%#010x\n"
           "Value:\t\t%#x\n"
           "Setting bits:\t%#x\n"
           "Clearing bits:\t%#x\n"
           "Selecting bits:\t%#010x\n"
           , mask
           , a
           , a | mask
           , a & ~mask
           , a & mask
    );
}

Mögliche Ausgabe:

Promoted mask:  0x000000f0
Value:          0x12345678
Setting bits:   0x123456f8
Clearing bits:  0x12345608
Selecting bits: 0x00000070

Shift-Operatoren

Die bitweisen Schiebeoperator-Ausdrücke haben die Form

lhs << rhs (1)
lhs >> rhs (2)
**Hinweis:** Da der Text auf der Webseite ausschließlich aus HTML-Tags, C++-Operatoren (`<<` und `>>`) und Platzhaltervariablen (`lhs`, `rhs`) besteht, die gemäß den Anweisungen nicht übersetzt werden sollen, bleibt der Inhalt unverändert. Die numerischen Referenzen (1) und (2) sind ebenfalls unverändert zu belassen.
1) Linksverschiebung von lhs um rhs Bits
2) Rechtsshift von lhs um rhs Bits

wobei

lhs , rhs - Ausdrücke ganzzahligen Typs

Zunächst werden Integer-Promotions separat für jeden Operanden durchgeführt (Hinweis: Dies unterscheidet sich von anderen binären arithmetischen Operatoren, die alle übliche arithmetische Konvertierungen durchführen). Der Typ des Ergebnisses ist der Typ des lhs nach der Promotion.

Das Verhalten ist undefiniert, wenn rhs negativ ist oder größer oder gleich der Anzahl der Bits im promoted lhs ist.

Für vorzeichenlose lhs ist der Wert von LHS << RHS der Wert von LHS * 2 RHS
, reduziert modulo Maximalwert des Rückgabetyps plus 1 (das heißt, bitweiser Linksshift wird durchgeführt und die Bits, die aus dem Zieltyp hinausgeschoben werden, werden verworfen). Für vorzeichenbehaftete lhs mit nichtnegativen Werten ist der Wert von LHS << RHS gleich LHS * 2 RHS
, wenn er im höhergestuften Typ von lhs darstellbar ist, andernfalls ist das Verhalten undefiniert.

Für vorzeichenlose lhs und für vorzeichenbehaftete lhs mit nichtnegativen Werten ist der Wert von LHS >> RHS der ganzzahlige Teil von LHS / 2 RHS
. Für negatives LHS ist der Wert von LHS >> RHS implementierungsdefiniert, wobei in den meisten Implementierungen dies einen arithmetischen Rechtsshift durchführt (sodass das Ergebnis negativ bleibt). Daher füllt in den meisten Implementierungen das Rechtsschieben eines vorzeichenbehafteten LHS die neuen höherwertigen Bits mit dem ursprünglichen Vorzeichenbit (d.h. mit 0, wenn es nicht-negativ war, und mit 1, wenn es negativ war).

#include <stdio.h>
enum {ONE=1, TWO=2};
int main(void)
{
    char c = 0x10;
    unsigned long long ulong_num = 0x123;
    printf("0x123 << 1  = %#llx\n"
           "0x123 << 63 = %#llx\n"   // Überlauf schneidet hohe Bits bei vorzeichenlosen Zahlen ab
           "0x10  << 10 = %#x\n",    // char wird zu int heraufgestuft
           ulong_num << 1, ulong_num << 63, c << 10);
    long long long_num = -1000;
    printf("-1000 >> 1 = %lld\n", long_num >> ONE);  // implementierungsdefiniert
}

Mögliche Ausgabe:

0x123 << 1  = 0x246
0x123 << 63 = 0x8000000000000000
0x10  << 10 = 0x4000
-1000 >> 1 = -500

Referenzen

  • C17-Standard (ISO/IEC 9899:2018):
  • 6.5.3.3 Unäre arithmetische Operatoren (S. 64)
  • 6.5.5 Multiplikative Operatoren (S. 66)
  • 6.5.6 Additive Operatoren (S. 66-68)
  • 6.5.7 Bitweise Schiebeoperatoren (S. 68)
  • 6.5.10 Bitweiser UND-Operator (S. 70)
  • 6.5.11 Bitweiser exklusiver ODER-Operator (S. 70)
  • 6.5.12 Bitweiser inklusiver ODER-Operator (S. 70-71)
  • C11-Standard (ISO/IEC 9899:2011):
  • 6.5.3.3 Unäre arithmetische Operatoren (S: 89)
  • 6.5.5 Multiplikative Operatoren (S: 92)
  • 6.5.6 Additive Operatoren (S: 92-94)
  • 6.5.7 Bitweise Verschiebeoperatoren (S: 94-95)
  • 6.5.10 Bitweiser UND-Operator (S: 97)
  • 6.5.11 Bitweiser exklusiver ODER-Operator (S: 98)
  • 6.5.12 Bitweiser inklusiver ODER-Operator (S: 98)
  • C99-Standard (ISO/IEC 9899:1999):
  • 6.5.3.3 Unäre arithmetische Operatoren (S. 79)
  • 6.5.5 Multiplikative Operatoren (S. 82)
  • 6.5.6 Additive Operatoren (S. 82-84)
  • 6.5.7 Bitweise Verschiebeoperatoren (S. 84-85)
  • 6.5.10 Bitweiser UND-Operator (S. 87)
  • 6.5.11 Bitweiser exklusiver ODER-Operator (S. 88)
  • 6.5.12 Bitweiser inklusiver ODER-Operator (S. 88)
  • C89/C90 Standard (ISO/IEC 9899:1990):
  • 3.3.3.3 Unäre arithmetische Operatoren
  • 3.3.5 Multiplikative Operatoren
  • 3.3.6 Additive Operatoren
  • 3.3.7 Bitweise Verschiebeoperatoren
  • 3.3.10 Bitweiser UND-Operator
  • 3.3.11 Bitweiser exklusiver ODER-Operator
  • 3.3.12 Bitweiser inklusiver ODER-Operator

Siehe auch

Operator-Präzedenz

Häufige Operatoren
Zuweisung Inkrement
Dekrement
Arithmetisch Logisch Vergleich Member-
zugriff
Sonstige

a = b
a + = b
a - = b
a * = b
a / = b
a % = b
a & = b
a | = b
a ^ = b
a <<= b
a >>= b

++ a
-- a
a ++
a --

+ a
- a
a + b
a - b
a * b
a / b
a % b
~a
a & b
a | b
a ^ b
a << b
a >> b

! a
a && b
a || b

a == b
a ! = b
a < b
a > b
a <= b
a >= b

a [ b ]
* a
& a
a - > b
a. b

a ( ... )
a, b
( type ) a
a ? b : c
sizeof


_Alignof
(seit C11)
(bis C23)

alignof
(seit C23)

C++ Dokumentation für Arithmetische Operatoren