Namensräume
Varianten
Aktionen

Arithmetische Operatoren

Von cppreference.com
< c‎ | Sprache

Arithmetische Operatoren wenden Standard-Rechenoperationen auf ihre Operanden an.

Operator Operatorname Beispiel Ergebnis
+ unäres Plus +a der Wert von a nach den Promotionen
- 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
% remainder a % b der Rest von a geteilt durch b
~ Bitweises NICHT ~a das bitweise NICHT von a
& Bitweises UND a & b das bitweise UND von a und b
| Bitweises ODER a | b das bitweise ODER von a und b
^ Bitweises XOR a ^ b das bitweise XOR von a und b
<< Bitweise Linksverschiebung a << b a um b Stellen nach links verschoben
>> Bitweise Rechtsverschiebung a >> b a um b Stellen nach rechts verschoben

Inhalt

[editieren] Überläufe

Arithmetik mit vorzeichenlosen ganzen Zahlen wird immer modulo 2n
durchgeführt, wobei n die Anzahl der Bits in dieser spezifischen Ganzzahl ist. Z.B. für unsigned int ergibt die Addition von eins zu UINT_MAX 0, und die Subtraktion von eins von 0 ergibt UINT_MAX.

Wenn bei der arithmetischen Operation mit vorzeichenbehafteten ganzen Zahlen ein Überlauf auftritt (das Ergebnis passt nicht in den Ergebnistyp), ist das Verhalten undefiniert: Es kann gemäß den Regeln der Darstellung (typischerweise 2er-Komplement) umbrechen, es kann auf einigen Plattformen oder aufgrund von Compiler-Optionen (z. B. -ftrapv in GCC und Clang) einen Fehler auslösen oder vom Compiler vollständig wegoptimiert werden.

[editieren] Gleitkomma-Umgebung

Wenn #pragma STDC FENV_ACCESS auf ON gesetzt ist, folgen alle Gleitkomma-Arithmetikoperatoren der aktuellen Rundungsrichtung für Gleitkommazahlen und melden Gleitkomma-Rechenfehler wie in math_errhandling angegeben, es sei denn, sie sind Teil eines statischen Initialisierers (in diesem Fall werden keine Gleitkomma-Ausnahmen ausgelöst und der Rundungsmodus ist "nächstliegend").

[editieren] Gleitkomma-Kontraktion

Sofern #pragma STDC FP_CONTRACT nicht auf OFF gesetzt ist, kann die gesamte Gleitkomma-Arithmetik so durchgeführt werden, als ob die Zwischenergebnisse unendliche Reichweite und Präzision hätten, d. h. Optimierungen, die Rundungsfehler und Gleitkomma-Ausnahmen weglassen, die beobachtet würden, wenn der Ausdruck exakt wie geschrieben ausgewertet würde. Dies erlaubt zum Beispiel die Implementierung von (x*y) + z mit einer einzigen fusionierten Multiply-Add-CPU-Anweisung oder die Optimierung von a = x*x*x*x; als tmp = x*x; a = tmp*tmp.

Unabhängig von der Kontraktion können Zwischenergebnisse der Gleitkomma-Arithmetik eine Reichweite und Präzision haben, die sich von der durch ihren Typ angezeigten unterscheidet; siehe FLT_EVAL_METHOD.

[editieren] Unäre Arithmetik

Die unären arithmetischen Operator-Ausdrücke haben die Form

+ expression (1)
- expression (2)
1) unäres Plus (Promotion)
2) unäres Minus (Negation)
expression - Ausdruck eines jeden arithmetischen Typs

Sowohl das unäre Plus als auch das unäre Minus wenden zuerst Ganzzahl-Promotionen auf ihren Operanden an, und dann

  • gibt das unäre Plus den Wert nach der Promotion zurück
  • gibt das unäre Minus das Negative des Wertes nach der Promotion zurück (außer dass das Negative einer NaN eine andere NaN ist)

Der Typ des Ausdrucks ist der Typ nach der Promotion, und die Wertkategorie ist nicht-lvalue.

[editieren] Hinweise

Das unäre Minus ruft undefiniertes Verhalten aufgrund eines Überlaufs bei vorzeichenbehafteten Ganzzahlen hervor, wenn es auf INT_MIN, LONG_MIN oder LLONG_MIN angewendet wird, auf typischen (2er-Komplement) Plattformen.

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

#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);
 
    // Defined behavior since arithmetic is performed for unsigned integer.
    // Hence, the calculation is (-1) modulo (2 raised to n) = UINT_MAX, where n is
    // the number of bits of unsigned int. If unsigned int is 32-bit long, then this
    // gives (-1) modulo (2 raised to 32) = 4294967295
    printf("-1, where 1 is unsigned: %u\n", -1u); 
 
    // Undefined behavior because the mathematical value of -INT_MIN = INT_MAX + 1
    // (i.e. 1 more than the maximum possible value for signed int)
    //
    // printf("%d\n", -INT_MIN);
 
    // Undefined behavior because the mathematical value of -LONG_MIN = LONG_MAX + 1
    // (i.e. 1 more than the maximum possible value for signed long)
    //
    // printf("%ld\n", -LONG_MIN);
 
    // Undefined behavior because the mathematical value of -LLONG_MIN = LLONG_MAX + 1
    // (i.e. 1 more than the maximum possible value for 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

[editieren] Additive Operatoren

Die binären additiven arithmetischen Operator-Ausdrücke haben die Form

lhs + rhs (1)
lhs - rhs (2)
1) Addition: lhs und rhs müssen eines der folgenden sein
  • beide haben arithmetische Typen, einschließlich komplexer und imaginärer Zahlen
  • einer ist ein Zeiger auf einen vollständigen Objekttyp, der andere hat einen Ganzzahltyp
2) Subtraktion: lhs und rhs müssen eines der folgenden sein
  • beide haben arithmetische Typen, einschließlich komplexer und imaginärer Zahlen
  • lhs hat einen Zeiger auf einen vollständigen Objekttyp, rhs hat einen Ganzzahltyp
  • beide sind Zeiger auf vollständige Objekte von kompatiblen Typen, wobei Qualifizierer ignoriert werden

[editieren] Arithmetische Addition und Subtraktion

Wenn beide Operanden arithmetische Typen haben, dann

  • werden zuerst übliche arithmetische Konversionen durchgeführt
  • dann werden die Werte der Operanden nach den Konversionen gemäß den üblichen mathematischen Regeln addiert oder subtrahiert (bei der Subtraktion wird rhs von lhs subtrahiert), außer dass
  • wenn ein Operand NaN ist, ist das Ergebnis NaN
  • unendlich minus unendlich ist NaN und FE_INVALID wird ausgelöst
  • unendlich plus negativer Unendlichkeit ist NaN und FE_INVALID wird ausgelöst

Die Addition und Subtraktion von komplexen und imaginären Zahlen ist 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 Konversionen bestimmt)

+ 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

[editieren] Zeiger-Arithmetik

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

Das Verhalten ist nur dann definiert, wenn sowohl der ursprüngliche Zeiger als auch der Ergebniszeiger auf Elemente desselben Arrays oder eine Position hinter dem Ende dieses 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 dem Index I (oder eine Position dahinter) zeigt und P2 auf ein Element desselben Arrays mit dem Index J (oder eine Position dahinter) zeigt, dann
  • P1-P2 hat den Wert gleich I-J und den Typ ptrdiff_t (ein vorzeichenbehafteter Ganzzahltyp, typischerweise halb so groß wie die Größe des größten Objekts, das deklariert werden kann)

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

Für die Zwecke der Zeiger-Arithmetik 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]

[editieren] Multiplikative Operatoren

Die binären multiplikativen arithmetischen Operator-Ausdrü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

[editieren] Multiplikation

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

  • wenn ein Operand NaN ist, ist das Ergebnis NaN
  • Multiplikation von Unendlich mit Null ergibt NaN und FE_INVALID wird ausgelöst
  • Multiplikation von Unendlich mit einer Nicht-Null ergibt Unendlich (auch für komplexe Argumente)

Da in C jeder komplexe Wert mit mindestens einem unendlichen Teil ein Unendlich ist, auch wenn sein anderer Teil eine NaN ist, gelten die üblichen arithmetischen Regeln nicht für die komplexe-komplexe Multiplikation. Andere Kombinationen von Gleitkomma-Operanden 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 darf die komplexe Multiplikation Zwischenergebnisse nicht überlaufen, außer wenn #pragma STDC CX_LIMITED_RANGE auf ON gesetzt ist, in diesem Fall kann der Wert berechnet werden, als ob (x+iy)×(u+iv) = (xu-yv)+i(yu+xv), da der Programmierer die Verantwortung für die Begrenzung des Wertebereichs der Operanden und die Behandlung von Unendlichkeiten übernimmt.

Trotz der Zulassung von überflüssigen Überläufen kann die komplexe Multiplikation fälschlicherweise Gleitkomma-Ausnahmen auslösen (andernfalls ist es prohibitiv schwierig, nicht überlaufende Versionen zu implementieren).

#include <stdio.h>
#include <stdio.h>
#include <complex.h>
#include <math.h>
int main(void)
{
 
 
// TODO simpler cases, take some from C++
 
 
   double complex z = (1 + 0*I) * (INFINITY + I*INFINITY);
// textbook formula would give
// (1+i0)(∞+i∞) ⇒ (1×∞ – 0×∞) + i(0×∞+1×∞) ⇒ NaN + I*NaN
// but C gives a complex infinity
   printf("%f + i*%f\n", creal(z), cimag(z));
 
// textbook formula would give
// cexp(∞+iNaN) ⇒ exp(∞)×(cis(NaN)) ⇒ NaN + I*NaN
// but C gives  ±∞+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

[editieren] Division

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

  • wenn der Typ nach den üblichen arithmetischen Konversionen ein Ganzzahltyp ist, ist das Ergebnis der algebraische Quotient (kein Bruch), gerundet in implementierungsdefinierter Richtung(bis C99)abgeschnitten zur Null(seit C99)
  • wenn ein Operand NaN ist, ist das Ergebnis 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.

Da in C jeder komplexe Wert mit mindestens einem unendlichen Teil eine Unendlichkeit ist, auch wenn sein anderer Teil eine NaN ist, gelten die üblichen arithmetischen Regeln nicht für die komplexe-komplexe Division. Andere Kombinationen von Gleitkomma-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 darf die komplexe Division Zwischenergebnisse nicht überlaufen, außer wenn #pragma STDC CX_LIMITED_RANGE auf ON gesetzt ist, in diesem Fall kann der Wert berechnet werden, als ob (x+iy)/(u+iv) = [(xu+yv)+i(yu-xv)]/(u2
+v2
)
, da der Programmierer die Verantwortung für die Begrenzung des Wertebereichs der Operanden und die Behandlung von Unendlichkeiten übernimmt.

Trotz der Zulassung von überflüssigen Überläufen kann die komplexe Division fälschlicherweise Gleitkomma-Ausnahmen auslösen (andernfalls ist es prohibitiv schwierig, nicht überlaufende Versionen zu implementieren).

Wenn der zweite Operand Null ist, ist das Verhalten undefiniert, es sei denn, wenn die IEEE-Gleitkomma-Arithmetik unterstützt wird und die Gleitkomma-Division stattfindet, dann

  • Die Division einer Nicht-Null-Zahl durch ±0.0 ergibt die korrekt vorzeichenbehaftete Unendlichkeit und FE_DIVBYZERO wird ausgelöst
  • Die Division von 0.0 durch 0.0 ergibt NaN und FE_INVALID wird ausgelöst

[editieren] Rest

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

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 nicht im Ergebnistyp darstellbar ist, ist das Verhalten sowohl von a/b als auch von a%b undefiniert (das bedeutet, dass INT_MIN%-1 auf 2er-Komplement-Systemen undefiniert ist).

Hinweis: Der Rest-Operator funktioniert nicht mit Gleitkommatypen. Die Bibliotheksfunktion fmod bietet diese Funktionalität.

[editieren] Bitweise Logik

Die bitweisen arithmetischen Operator-Ausdrücke haben die Form

~ rhs (1)
lhs & rhs (2)
lhs | rhs (3)
lhs ^ rhs (4)
1) bitweises NICHT
2) bitweises UND
3) bitweises ODER
4) bitweises XOR

wobei

lhs, rhs - Ausdrücke vom Ganzzahltyp

Zuerst führen die Operatoren &, ^ und | übliche arithmetische Konversionen auf beiden Operanden durch, und der Operator ~ führt Ganzzahl-Promotionen auf seinem einzigen Operanden durch.

Dann werden die entsprechenden binären Logikoperatoren bitweise angewendet; das heißt, jedes Bit des Ergebnisses wird entsprechend der logischen Operation (NICHT, UND, ODER oder XOR), angewendet auf die entsprechenden Bits der Operanden, gesetzt oder gelöscht.

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

Hinweis: Für vorzeichenlose Typen (nach der Promotion) ist der Ausdruck ~E äquivalent zum maximal 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

[editieren] Shift-Operatoren

Die bitweisen Shift-Operator-Ausdrücke haben die Form

lhs << rhs (1)
lhs >> rhs (2)
1) Linksverschiebung von lhs um rhs Bits
2) Rechtsverschiebung von lhs um rhs Bits

wobei

lhs, rhs - Ausdrücke vom Ganzzahltyp

Zuerst werden Ganzzahl-Promotionen einzeln auf jeden Operanden angewendet (Hinweis: dies ist im Gegensatz zu anderen binären arithmetischen Operatoren, die alle übliche arithmetische Konversionen durchführen). Der Typ des Ergebnisses ist der Typ von lhs nach der Promotion.

Das Verhalten ist undefiniert, wenn rhs negativ ist oder größer oder gleich der Anzahl der Bits in dem aufgerufenen lhs ist.

Für vorzeichenloses lhs ist der Wert von LHS << RHS der Wert von LHS * 2RHS
, reduziert modulo dem Maximalwert des Rückgabetyps plus 1 (d. h. es wird eine bitweise Linksverschiebung durchgeführt und die Bits, die aus dem Zieltyp herausgeschoben werden, werden verworfen). Für vorzeichenbehaftetes lhs mit nicht-negativen Werten ist der Wert von LHS << RHS LHS * 2RHS
, wenn er im aufgerufenen Typ von lhs darstellbar ist, andernfalls ist das Verhalten undefiniert.

Für vorzeichenloses lhs und für vorzeichenbehaftetes lhs mit nicht-negativen Werten ist der Wert von LHS >> RHS der Ganzzahlteil von LHS / 2RHS
. Für negatives LHS ist der Wert von LHS >> RHS implementierungsdefiniert, wobei die meisten Implementierungen eine arithmetische Rechtsverschiebung durchführen (sodass das Ergebnis negativ bleibt). So füllen die meisten Implementierungen bei einer Rechtsverschiebung 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"   // overflow truncates high bits for unsigned numbers
           "0x10  << 10 = %#x\n",    // char is promoted to int
           ulong_num << 1, ulong_num << 63, c << 10);
    long long long_num = -1000;
    printf("-1000 >> 1 = %lld\n", long_num >> ONE);  // implementation defined
}

Mögliche Ausgabe

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

[editieren] 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 Shift-Operatoren (S. 68)
  • 6.5.10 Bitwise AND Operator (S. 70)
  • 6.5.11 Bitwise Exclusive OR Operator (S. 70)
  • 6.5.12 Bitwise Inclusive OR 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 Shift-Operatoren (S. 94-95)
  • 6.5.10 Bitwise AND Operator (S. 97)
  • 6.5.11 Bitwise Exclusive OR Operator (S. 98)
  • 6.5.12 Bitwise Inclusive OR 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 Shift-Operatoren (S. 84-85)
  • 6.5.10 Bitwise AND Operator (S. 87)
  • 6.5.11 Bitwise Exclusive OR Operator (S. 88)
  • 6.5.12 Bitwise Inclusive OR 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 Shift-Operatoren
  • 3.3.10 Bitwise AND Operator
  • 3.3.11 Bitwise Exclusive OR Operator
  • 3.3.12 Bitwise Inclusive OR Operator

[editieren] Siehe auch

Operatorrangfolge

Häufige Operatoren
Zuweisung Inkrement
Dekrement
Arithmetik Logisch Vergleich Member
Zugriff
Sonstiges

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