Arithmetic Operators
| Operator | Function |
|---|---|
+ (unary) | Unary plus |
- (unary) | Unary minus |
* (binary) | Multiplication |
/ | Division |
% | Modulo |
+ (binary) | Addition |
- (binary) | Subtraction |
Unary and binary operators
A unary operator (also called a monadic operator) is an operator with only one operand, while a binary operator (also called a dyadic operator) has two operands. For example, the plus sign in 1 + 2 is a binary operator, with 1 and 2 as its two operands. In addition, C++ has exactly one ternary operator, ?:.
Among arithmetic operators, there are two unary operators (unary plus and unary minus) and five binary operators (multiplication, division, modulo, addition, and subtraction). Unary operators have the highest precedence.
The modulo operator % means calculating the remainder obtained by dividing two integers, that is, finding the remainder.
When - is a binary operator, it performs subtraction, as in 2-1; when it is a unary operator, it performs negation, as in -1.
It is used as follows:
op=x-y*z
its value computed by op follows the usual mathematical precedence of addition, subtraction, multiplication, and division: operations with higher precedence are performed first; operations with equal precedence are performed according to associativity; and parentheses increase precedence.
Type Conversion in Arithmetic Operations
For binary arithmetic operators, when the types of the two variables involved in an operation are the same, no type conversion occurs, and the outcome is stored using the type of the participating variables. Otherwise, type conversion occurs so that the types of the two variables become consistent. See type conversion for the conversion rules.
For example, consider an integer (int) variable and another variable of type double-precision floating point (double):
- Evaluating
x/3is an integer; - Evaluating
x/3.0is a double-precision floating-point value; - Evaluating
x/yis a double-precision floating-point value; - Evaluating
x*1/3is an integer; - Evaluating
x*1.0/3is a double-precision floating-point value;
Bitwise Operators
See also: Bitwise Operations.
| Operator | Function |
|---|---|
~ | Bitwise NOT |
& (binary) | Bitwise AND |
| ` | ` |
^ | Bitwise XOR |
<< | Bitwise left shift |
>> | Bitwise right shift |
For the meaning of bitwise operations, see the Bitwise Operations page. Note that bitwise operations have lower precedence than arithmetic operators (except for bitwise NOT), while bitwise AND, bitwise OR, and XOR have lower precedence than comparison operators (see the complete C++ operator precedence table). Therefore, take extra care when using them and add parentheses when necessary.
The behavior of a shift operation is undefined in the following cases:
- The right operand (that is, the number of positions to shift) is negative;
- The right operand is greater than or equal to the number of bits in the left operand;
For example, for a variable a of type int32_t, both a<<-1 and a<<32 are undefined.
For a left-shift operation on a signed nonnegative number, you must ensure that the shifted result can be represented by the original type; otherwise, the behavior is also undefined.1 Performing a left shift on a negative number is also undefined.2
For a right-shift operation, excess bits on the right are discarded, while the behavior on the left is more complicated: for unsigned numbers, is added on the left3; for signed numbers, the most significant bit (which is the sign bit: for nonnegative numbers and for negative numbers) is replicated to fill the left side4.
Increment/Decrement Operators
Sometimes we need to increase a variable by 1 (increment) or decrease it by 1 (decrement). This is where the increment operator ++ and decrement operator -- come in handy.
Increment/decrement operators can be placed before or after a variable. They are called prefixes when placed before a variable and suffixes when placed after it. When used alone, prefixes and suffixes need no special distinction; if its value from that expression is used, however, attention is required. See the examples below for details. For more information, see the examples section of the introduction to references.
i = 100;
op1 = i++; // op1 = 100, first op1 = i, then i = i + 1
i = 100;
op2 = ++i; // op2 = 101, first i = i + 1, then assign op2
i = 100;
op3 = i--; // op3 = 100, first assign op3, then i = i - 1
i = 100;
op4 = --i; // op4 = 99, first i = i - 1, then assign op4
Compound Assignment Operators
Compound assignment operators are actually abbreviated forms of expressions. They can be divided into compound arithmetic operators +=, -=, *=, /=, %= and compound bitwise operators &=, |=, ^=, <<=, >>=.
For example, op = op + 2 can be written as op += 2, op = op - 2 can be written as op -= 2, and op= op * 2 can be written as op *= 2.
Conditional Operator
The conditional operator can be regarded as an abbreviation for an if statement. In a ? b : c, if expression a is true, the outcome of the conditional expression is b; otherwise, the outcome is c.
Comparison Operators
| Operator | Function |
|---|---|
> | Greater than |
>= | Greater than or equal to |
< | Less than |
<= | Less than or equal to |
== | Equal to |
!= | Not equal to |
In particular, note that the equality operator == must be distinguished from the assignment operator =. This is especially important in conditional statements.
if (op=1) and if (op==1) look similar, but their actual functions differ greatly. The first statement assigns a value to op; if the assigned value is nonzero, it is true, so that condition of that expression is always satisfied and cannot serve as a test. The second statement is the one that tests its value from op.
Logical Operators
| Operator | Function |
|---|---|
&& | Logical AND |
| ` | |
! | Logical NOT |
Result = op1 && op2; // Result is true when both op1 and op2 are true
Result = op1 || op2; // Result is true when either op1 or op2 is true
Result = !op1; // Result is true when op1 is false
The built-in operators && and || perform short-circuit evaluation (if the outcome is already known after evaluating the first operand, the second operand is not evaluated). Overloaded operators do not have this property and always evaluate both operands.
Comma Operator
The comma operator separates multiple expressions. The separated expressions are evaluated in order from left to right, and its value from the entire expression is its value from the last expression. The comma expression has the lowest precedence of all operators.
exp1, exp2, exp3; // The final value is the outcome of evaluating exp3.
Result = 1 + 2, 3 + 4, 5 + 6;
// Result is 3 rather than 11, because the assignment operator "=" has higher precedence
// than the comma operator, so assignment is performed before the comma operations.
Result = (1 + 2, 3 + 4, 5 + 6);
// To make its value from Result be the outcome of the comma operation, the entire expression
// should be enclosed in parentheses to increase its precedence. Only then is its value from Result 11.
Member Access Operators
| Operator | Function |
|---|---|
[] | Array subscript |
. | Object member |
& (unary) | Take address / obtain reference |
* (unary) | Indirection / dereference |
-> | Pointer member |
These operators are used to access members or memory of an object. Except for the last operator, all of the operators above can be overloaded. For material related to &, *, and ->, read the Pointers and References tutorials. Two rarely used operators, .* and ->*, are omitted here; for their specific usage, see the C++ language reference.
auto result1 = v[1]; // Get the object whose subscript in v is 2
auto result2 = p.q; // Get member q of object p
auto result3 = p -> q; // Get member q of the object pointed to by p, equivalent to (*p).q
auto result4 = &v; // Get the pointer to v
auto result5 = *v; // Get the object pointed to by pointer v
Complete C++ Operator Precedence Table
From C++ operator precedence - cppreference, with modifications.
| Operator | Description | Example | Overloadable |
|---|---|---|---|
| Level 1 | |||
:: | Scope resolution operator | Class::age = 2; | Not overloadable |
| Level 2 | |||
++ | Postfix increment operator | for (int i = 0; i < 10; i++) cout << i; | Overloadable |
-- | Postfix decrement operator | for (int i = 10; i > 0; i--) cout << i; | Overloadable |
type() type{} | Explicit type conversion | unsigned int a = unsigned(3.14); | Overloadable |
() | Function call | isdigit('1') | Overloadable |
[] | Array element access | array[4] = 2; | Overloadable |
. | Object member access | obj.age = 34; | Not overloadable |
-> | Pointer member access | ptr->age = 34; | Overloadable |
| Level 3 (right-to-left associativity) | |||
++ | Prefix increment operator | for (i = 0; i < 10; ++i) cout << i; | Overloadable |
-- | Prefix decrement operator | for (i = 10; i > 0; --i) cout << i; | Overloadable |
+ | Unary plus | int i = +1; | Overloadable |
- | Unary minus | int i = -1; | Overloadable |
! | Logical NOT | if (!done) … | Overloadable |
~ | Bitwise NOT | flags = ~flags; | Overloadable |
(type) | C-style explicit type conversion | int i = (int) floatNum; | Overloadable |
* | Pointer dereference | int data = *intPtr; | Overloadable |
& | Address-of | int *intPtr = &data; | Overloadable |
sizeof | Return type size | int size = sizeof floatNum; int size = sizeof(float); | Not overloadable |
new | Dynamic object allocation | long *pVar = new long; MyClass *ptr = new MyClass(args); | Overloadable |
new [] | Dynamic array allocation | long *array = new long[n]; | Overloadable |
delete | Dynamic object destruction | delete pVar; | Overloadable |
delete [] | Dynamic array destruction | delete [] array; | Overloadable |
| Level 4 | |||
.* | Class-object member pointer | obj.*var = 24; | Not overloadable |
->* | Class-pointer member pointer | ptr->*var = 24; | Overloadable |
| Level 5 | |||
* | Multiplication | int i = 2 * 4; | Overloadable |
/ | Division | float f = 10.0 / 3.0; | Overloadable |
% | Modulo | int rem = 4 % 3; | Overloadable |
| Level 6 | |||
+ | Addition | int i = 2 + 3; | Overloadable |
- | Subtraction | int i = 5 - 1; | Overloadable |
| Level 7 | |||
<< | Bitwise left shift | int flags = 33 << 1; | Overloadable |
>> | Bitwise right shift | int flags = 33 >> 1; | Overloadable |
| Level 8 | |||
<=> | Three-way comparison operator | if ((i <=> 42) < 0) ... | Overloadable |
| Level 9 | |||
< | Less than | if (i < 42) ... | Overloadable |
<= | Less than or equal to | if (i <= 42) ... | Overloadable |
> | Greater than | if (i > 42) ... | Overloadable |
>= | Greater than or equal to | if (i >= 42) ... | Overloadable |
| Level 10 | |||
== | Equal to | if (i == 42) ... | Overloadable |
!= | Not equal to | if (i != 42) ... | Overloadable |
| Level 11 | |||
& | Bitwise AND | flags = flags & 42; | Overloadable |
| Level 12 | |||
^ | Bitwise XOR | flags = flags ^ 42; | Overloadable |
| Level 13 | |||
| ` | ` | Bitwise OR | `flags = flags |
| Level 14 | |||
&& | Logical AND | if (conditionA && conditionB) ... | Overloadable |
| Level 15 | |||
| ` | ` | Logical OR | |
| Level 16 (right-to-left associativity) | |||
? : | Conditional operator | int i = a > b ? a : b; | Not overloadable |
throw | Throw expression | throw EClass("Message"); | Not overloadable |
= | Assignment | int a = b; | Overloadable |
+= | Add and assign | a += 3; | Overloadable |
-= | Subtract and assign | b -= 4; | Overloadable |
*= | Multiply and assign | a *= 5; | Overloadable |
/= | Divide and assign | a /= 2; | Overloadable |
%= | Modulo and assign | a %= 3; | Overloadable |
<<= | Bitwise left-shift assignment | flags <<= 2; | Overloadable |
>>= | Bitwise right-shift assignment | flags >>= 2; | Overloadable |
&= | Bitwise AND assignment | flags &= new_flags; | Overloadable |
^= | Bitwise XOR assignment | flags ^= new_flags; | Overloadable |
| ` | =` | Bitwise OR assignment | `flags |
| Level 17 | |||
, | Comma separator | for (i = 0, j = 0; i < 10; i++, j++) ... | Overloadable |
Note that the table does not list operators such as const_cast, static_cast, dynamic_cast, reinterpret_cast, typeid, sizeof..., noexcept, and alignof, because their syntax is the same as a function call and cannot be ambiguous.
References and notes
Footnotes
-
Before C++20, if the original value had a signed type and the shifted result could be represented by the unsigned version of the original type, the outcome was converted to the corresponding signed value; otherwise, the behavior was undefined. For left shifts of unsigned numbers, bits shifted out of the outcome type were discarded. Starting with C++20,
a << bis specified as its value from modulo ( is the bit width of the outcome type), meaning that for both signed and unsigned numbers, a left shift directly discards bits shifted out of the outcome type (that is, arithmetic left shift / logical left shift). ↩ -
That is, logical right shift. ↩
-
That is, arithmetic right shift. Before C++20, right shifting a signed number was implementation-defined; most implementations used arithmetic right shift. Starting with C++20,
a >> bis specified as , so right-shifting a signed number is an arithmetic right shift. ↩