Operators in C and C++
This is a list of operators in the C and C++programming languages.
All listed operators are in C++ and lacking indication otherwise, in C as well. Some tables include a "In C" column that indicates whether an operator is also in C. Note that C does not support operator overloading.
When not overloaded, for the operators &&
, ||
, and ,
(the comma operator), there is a sequence point after the evaluation of the first operand.
Most of the operators available in C and C++ are also available in other C-family languages such as C#, D, Java, Perl, and PHP with the same precedence, associativity, and semantics.
Many operators specified by a sequence of symbols are commonly referred to by a name that consists of the name of each symbol. For example, +=
and -=
are often called "plus equal(s)" and "minus equal(s)", instead of the more verbose "assignment by addition" and "assignment by subtraction".
Operators
[edit]In the following tables, lower case letters such as a
and b
represent literal values, object/variable names, or l-values, as appropriate. R
, S
and T
stand for a data type, and K
for a class or enumeration type. Some operators have alternative spellings using digraphs and trigraphs or operator synonyms.
Arithmetic
[edit]C and C++ have the same arithmetic operators and all can be overloaded in C++.
Operation | Syntax | C++ prototype | ||
---|---|---|---|---|
in class K | outside class | |||
Addition | a + b | RK::operator+(Sb); | Roperator+(Ka,Sb); | |
Subtraction | a - b | RK::operator-(Sb); | Roperator-(Ka,Sb); | |
Unary plus; integer promotion | +a | RK::operator+(); | Roperator+(Ka); | |
Unary minus; additive inverse | -a | RK::operator-(); | Roperator-(Ka); | |
Multiplication | a * b | RK::operator*(Sb); | Roperator*(Ka,Sb); | |
Division | a / b | RK::operator/(Sb); | Roperator/(Ka,Sb); | |
Modulo[a] | a % b | RK::operator%(Sb); | Roperator%(Ka,Sb); | |
Prefix increment | ++a | R&K::operator++(); | R&operator++(K&a); | |
Postfix increment | a++ | RK::operator++(int); [b] | Roperator++(K&a,int); [b] | |
Prefix decrement | --a | R&K::operator--(); | R&operator--(K&a); | |
Postfix decrement | a-- | RK::operator--(int); [b] | Roperator--(K&a,int); [b] |
Relational
[edit]All relational (comparison) operators can be overloaded in C++. Since C++20, the inequality operator is automatically generated if operator==
is defined and all four relational operators are automatically generated if operator<=>
is defined.[1]
Operation | Syntax | In C | C++ prototype | ||
---|---|---|---|---|---|
in class K | outside class | ||||
Equal to | a == b | Yes | boolK::operator==(Sconst&b)const; | booloperator==(Kconst&a,Sconst&b); | |
Not equal to | a != b | Yes | boolK::operator!=(Sconst&b)const; | booloperator!=(Kconst&a,Sconst&b); | |
Greater than | a > b | Yes | boolK::operator>(Sconst&b)const; | booloperator>(Kconst&a,Sconst&b); | |
Less than | a < b | Yes | boolK::operator<(Sconst&b)const; | booloperator<(Kconst&a,Sconst&b); | |
Greater than or equal to | a >= b | Yes | boolK::operator>=(Sconst&b)const; | booloperator>=(Kconst&a,Sconst&b); | |
Less than or equal to | a <= b | Yes | boolK::operator<=(Sconst&b)const; | booloperator<=(Kconst&a,Sconst&b); | |
Three-way comparison[c][d] | a <=> b | No | autoK::operator<=>(constS&b); | autooperator<=>(constK&a,constS&b); |
Logical
[edit]C and C++ have the same logical operators and all can be overloaded in C++.
Note that overloading logical AND and OR is discouraged, because as overloaded operators they always evaluate both operands instead of providing the normal semantics of short-circuit evaluation.[2]
Operation | Syntax | C++ prototype | ||
---|---|---|---|---|
in class K | outside class | |||
NOT | !a | boolK::operator!(); | booloperator!(Ka); | |
AND | a && b | boolK::operator&&(Sb); | booloperator&&(Ka,Sb); | |
OR | a || b | boolK::operator||(Sb); | booloperator||(Ka,Sb); |
Bitwise
[edit]C and C++ have the same bitwise operators and all can be overloaded in C++.
Operation | Syntax | C++ prototype | ||
---|---|---|---|---|
in class K | outside class | |||
NOT | ~a | RK::operator~(); | Roperator~(Ka); | |
AND | a & b | RK::operator&(Sb); | Roperator&(Ka,Sb); | |
OR | a | b | RK::operator|(Sb); | Roperator|(Ka,Sb); | |
XOR | a ^ b | RK::operator^(Sb); | Roperator^(Ka,Sb); | |
Shift left[e] | a << b | RK::operator<<(Sb); | Roperator<<(Ka,Sb); | |
Shift right[e][f] | a >> b | RK::operator>>(Sb); | Roperator>>(Ka,Sb); |
Assignment
[edit]C and C++ have the same assignment operators and all can be overloaded in C++.
For the combination operators, a ⊚= b
(where ⊚
represents an operation) is equivalent to a = a ⊚ b
, except that a
is evaluated only once.
Operation | Syntax | C++ prototype | |
---|---|---|---|
in class K | outside class | ||
Assignment | a = b | R&K::operator=(Sb); | — |
Addition combination | a += b | R&K::operator+=(Sb); | R&operator+=(K&a,Sb); |
Subtraction combination | a -= b | R&K::operator-=(Sb); | R&operator-=(K&a,Sb); |
Multiplication combination | a *= b | R&K::operator*=(Sb); | R&operator*=(K&a,Sb); |
Division combination | a /= b | R&K::operator/=(Sb); | R&operator/=(K&a,Sb); |
Modulo combination | a %= b | R&K::operator%=(Sb); | R&operator%=(K&a,Sb); |
Bitwise AND combination | a &= b | R&K::operator&=(Sb); | R&operator&=(K&a,Sb); |
Bitwise OR combination | a |= b | R&K::operator|=(Sb); | R&operator|=(K&a,Sb); |
Bitwise XOR combination | a ^= b | R&K::operator^=(Sb); | R&operator^=(K&a,Sb); |
Bitwise left shift combination | a <<= b | R&K::operator<<=(Sb); | R&operator<<=(K&a,Sb); |
Bitwise right shift combination[g] | a >>= b | R&K::operator>>=(Sb); | R&operator>>=(K&a,Sb); |
Member and pointer
[edit]Operation | Syntax | Can overload | In C | C++ prototype | ||
---|---|---|---|---|---|---|
in class K | outside class | |||||
Subscript | a[b] a<:b:> [4] | Yes | Yes | R&K::operator[](Sb); R&K::operator[](Sb,...); [h] | — | |
Indirection (object pointed to by a) | *a | Yes | Yes | R&K::operator*(); | R&operator*(Ka); | |
Address-of (address of a) | &a | Yes[i] | Yes | R*K::operator&(); | R*operator&(Ka); | |
Structure dereference (member b of object pointed to by a) | a->b | Yes | Yes | R*K::operator->(); [j] | — | |
Structure reference (member b of object a) | a.b | No | Yes | — | ||
Member selected by pointer-to-memberb of object pointed to by a[k] | a->*b | Yes | No | R&K::operator->*(Sb); | R&operator->*(Ka,Sb); | |
Member of object a selected by pointer-to-memberb | a.*b | No | No | — |
Other
[edit]Operation | Syntax | Can overload | In C | C++ prototype | ||
---|---|---|---|---|---|---|
in class K | outside class | |||||
Function call | a(a1, a2) | Yes | Yes | RK::operator()(Sa,Tb,...); | — | |
Comma | a, b | Yes | Yes | RK::operator,(Sb); | Roperator,(Ka,Sb); | |
Ternary conditional | a ? b : c | No | Yes | — | ||
Scope resolution | a::b [l] | No | No | — | ||
User-defined literals[m][n] | "a"_b | Yes | No | — | Roperator""_b(Ta) | |
Sizeof | sizeof a [o]sizeof (R) | No | Yes | — | ||
Size of parameter pack[n] | sizeof...(Args) | No | No | — | ||
Alignof[n] | alignof(R) or _Alignof(R) [p] | No | Yes | — | ||
Decltype[n] | decltype (a) decltype (R) | No | No | — | ||
Type identification | typeid(a) typeid(R) | No | No | — | ||
Conversion (C-style cast) | (R)a | Yes | Yes | K::operatorR(); [5] | — | |
Conversion[q][6] | R(a) R{a} [n]auto(a) [h]auto{a} [h] | No | No | — | ||
static_cast conversion[r] | static_cast<R>(a) | Yes | No | K::operatorR(); explicitK::operatorR(); [n] | — | |
dynamic cast conversion | dynamic_cast<R>(a) | No | No | — | ||
const_cast conversion | const_cast<R>(a) | No | No | — | ||
reinterpret_cast conversion | reinterpret_cast<R>(a) | No | No | — | ||
Allocate storage | new R [s] | Yes | No | void*K::operatornew(size_tx); | void*operatornew(size_tx); | |
Allocate array | new R[n] [t] | Yes | No | void*K::operatornew[](size_ta); | void*operatornew[](size_ta); | |
Deallocate storage | delete a | Yes | No | voidK::operatordelete(void*a); | voidoperatordelete(void*a); | |
Deallocate array | delete[] a | Yes | No | voidK::operatordelete[](void*a); | voidoperatordelete[](void*a); | |
Exception check[n] | noexcept(a) | No | No | — |
Synonyms
[edit]C++ defines keywords to act as aliases for a number of operators:[7]
Keyword | Operator |
---|---|
and | && |
and_eq | &= |
bitand | & |
bitor | | |
compl | ~ |
not | ! |
not_eq | != |
or | || |
or_eq | |= |
xor | ^ |
xor_eq | ^= |
Each keyword is a different way to specify an operator and as such can be used instead of the corresponding symbolic variation. For example, (a > 0 and not flag)
and (a > 0 && !flag)
specify the same behavior. As another example, the bitand
keyword may be used to replace not only the bitwise-and operator but also the address-of operator, and it can be used to specify reference types (e.g., int bitand ref = n
).
The ISO C specification makes allowance for these keywords as preprocessor macros in the header file iso646.h
. For compatibility with C, C++ also provides the header iso646.h
, the inclusion of which has no effect. Until C++20, it also provided the corresponding header ciso646
which had no effect as well.
Expression evaluation order
[edit]During expression evaluation, the order in which sub-expressions are evaluated is determined by precedence and associativity. An operator with higher precedence is evaluated before a operator of lower precedence and the operands of an operator are evaluated based on associativity. The following table describes the precedence and associativity of the C and C++ operators. Operators are shown in groups of equal precedence with groups ordered in descending precedence from top to bottom (lower order is higher precedence).[8][9][10]
Operator precedence is not affected by overloading.
Order | Operator | Description | Associativity |
---|---|---|---|
1 highest | :: | Scope resolution (C++ only) | None |
2 | ++ | Postfix increment | Left-to-right |
-- | Postfix decrement | ||
() | Function call | ||
[] | Array subscripting | ||
. | Element selection by reference | ||
-> | Element selection through pointer | ||
typeid() | Run-time type information (C++ only) (see typeid) | ||
const_cast | Type cast (C++ only) (see const_cast) | ||
dynamic_cast | Type cast (C++ only) (see dynamic cast) | ||
reinterpret_cast | Type cast (C++ only) (see reinterpret_cast) | ||
static_cast | Type cast (C++ only) (see static_cast) | ||
3 | ++ | Prefix increment | Right-to-left |
-- | Prefix decrement | ||
+ | Unary plus | ||
- | Unary minus | ||
! | Logical NOT | ||
~ | Bitwise NOT (ones' complement) | ||
(type) | Type cast | ||
* | Indirection (dereference) | ||
& | Address-of | ||
sizeof | Sizeof | ||
_Alignof | Alignment requirement (since C11) | ||
new , new[] | Dynamic memory allocation (C++ only) | ||
delete , delete[] | Dynamic memory deallocation (C++ only) | ||
4 | .* | Pointer to member (C++ only) | Left-to-right |
->* | Pointer to member (C++ only) | ||
5 | * | Multiplication | Left-to-right |
/ | Division | ||
% | Modulo (remainder) | ||
6 | + | Addition | Left-to-right |
- | Subtraction | ||
7 | << | Bitwise left shift | Left-to-right |
>> | Bitwise right shift | ||
8 | <=> | Three-way comparison (Introduced in C++20 - C++ only) | Left-to-right |
9 | < | Less than | Left-to-right |
<= | Less than or equal to | ||
> | Greater than | ||
>= | Greater than or equal to | ||
10 | == | Equal to | Left-to-right |
!= | Not equal to | ||
11 | & | Bitwise AND | Left-to-right |
12 | ^ | Bitwise XOR (exclusive or) | Left-to-right |
13 | | | Bitwise OR (inclusive or) | Left-to-right |
14 | && | Logical AND | Left-to-right |
15 | || | Logical OR | Left-to-right |
16 | co_await | Coroutine processing (C++ only) | Right-to-left |
co_yield | |||
17 | ?: | Ternary conditional operator | Right-to-left |
= | Direct assignment | ||
+= | Assignment by sum | ||
-= | Assignment by difference | ||
*= | Assignment by product | ||
/= | Assignment by quotient | ||
%= | Assignment by remainder | ||
<<= | Assignment by bitwise left shift | ||
>>= | Assignment by bitwise right shift | ||
&= | Assignment by bitwise AND | ||
^= | Assignment by bitwise XOR | ||
|= | Assignment by bitwise OR | ||
throw | Throw operator (exceptions throwing, C++ only) | ||
18 lowest | , | Comma | Left-to-right |
Details
[edit]Although this table is adequate for describing most evaluation order, it does not describe a few details. The ternary operator allows any arbitrary expression as its middle operand, despite being listed as having higher precedence than the assignment and comma operators. Thus a ? b, c : d
is interpreted as a ? (b, c) : d
, and not as the meaningless (a ? b), (c : d)
. So, the expression in the middle of the conditional operator (between ?
and :
) is parsed as if parenthesized. Also, the immediate, un-parenthesized result of a C cast expression cannot be the operand of sizeof
. Therefore, sizeof (int) * x
is interpreted as (sizeof(int)) * x
and not sizeof ((int) * x)
.
Chained expressions
[edit]The precedence table determines the order of binding in chained expressions, when it is not expressly specified by parentheses.
- For example,
++x*3
is ambiguous without some precedence rule(s). The precedence table tells us that: x is 'bound' more tightly to ++ than to *, so that whatever ++ does (now or later—see below), it does it ONLY to x (and not tox*3
); it is equivalent to (++x
,x*3
). - Similarly, with
3*x++
, where though the post-fix ++ is designed to act AFTER the entire expression is evaluated, the precedence table makes it clear that ONLY x gets incremented (and NOT3*x
). In fact, the expression (tmp=x++
,3*tmp
) is evaluated with tmp being a temporary value. It is functionally equivalent to something like (tmp=3*x
,++x
,tmp
).

- Abstracting the issue of precedence or binding, consider the diagram above for the expression 3+2*y[i]++. The compiler's job is to resolve the diagram into an expression, one in which several unary operators (call them 3+( . ), 2*( . ), ( . )++ and ( . )[ i ]) are competing to bind to y. The order of precedence table resolves the final sub-expression they each act upon: ( . )[ i ] acts only on y, ( . )++ acts only on y[i], 2*( . ) acts only on y[i]++ and 3+( . ) acts 'only' on 2*((y[i])++). It is important to note that WHAT sub-expression gets acted on by each operator is clear from the precedence table but WHEN each operator acts is not resolved by the precedence table; in this example, the ( . )++ operator acts only on y[i] by the precedence rules but binding levels alone do not indicate the timing of the postfix ++ (the ( . )++ operator acts only after y[i] is evaluated in the expression).
Binding
[edit]The binding of operators in C and C++ is specified by a factored language grammar, rather than a precedence table. This creates some subtle conflicts. For example, in C, the syntax for a conditional expression is:
logical-OR-expression?expression:conditional-expression
while in C++ it is:
logical-OR-expression?expression:assignment-expression
Hence, the expression:
e = a < d ? a++ : a = d
is parsed differently in the two languages. In C, this expression is a syntax error, because the syntax for an assignment expression in C is:
unary-expression'='assignment-expression
In C++, it is parsed as:
e=(a<d?a++:(a=d))
which is a valid expression.[11][12]
To use the comma operator in a function call argument expression, variable assignment, or a comma-separated list, use of parentheses is required.[13][14] For example,
inta=1,b=2,weirdVariable=(++a,b),d=4;
Criticism of bitwise and equality operators precedence
[edit]The precedence of the bitwise logical operators has been criticized.[15] Conceptually, & and | are arithmetic operators like * and +.
The expression a&b==7
is syntactically parsed as a&(b==7)
whereas the expression a+b==7
is parsed as (a+b)==7
. This requires parentheses to be used more often than they otherwise would.
Historically, there was no syntactic distinction between the bitwise and logical operators. In BCPL, B and early C, the operators &&||
didn't exist. Instead &|
had different meaning depending on whether they are used in a 'truth-value context' (i.e. when a Boolean value was expected, for example in if(a==b&c){...}
it behaved as a logical operator, but in c=a&b
it behaved as a bitwise one). It was retained so as to keep backward compatibility with existing installations.[16]
Moreover, in C++ (and later versions of C) equality operations, with the exception of the three-way comparison operator, yield bool type values which are conceptually a single bit (1 or 0) and as such do not properly belong in "bitwise" operations.
Notes
[edit]- ^The modulus operator only supports integer operands; for floating point, a function such as
fmod
can be used. - ^ abcdThe
int
is a dummy parameter to differentiate between prefix and postfix. - ^About C++20 three-way comparison
- ^Possible return types:
std::weak_ordering
,std::strong_ordering
andstd::partial_ordering
to which they all are convertible to. - ^ abIn the context of iostreams in C++, writers often will refer to
<<
and>>
as the "put-to" or "stream insertion" and "get-from" or "stream extraction" operators, respectively. - ^ According to the C99 standard, the right shift of a negative number is implementation defined. Most implementations, e.g., the GCC,[3] use an arithmetic shift (i.e., sign extension), but a logical shift is possible.
- ^ According to the C99 standard, the right shift of a negative number is implementation defined. Most implementations, e.g., the GCC,[3] use an arithmetic shift (i.e., sign extension), but a logical shift is possible.
- ^ abcsince C++23
- ^The actual address of an object with an overloaded
operator &
can be obtained withstd::addressof
- ^The return type of
operator->()
must be a type for which the->
operation can be applied, such as a pointer type. Ifx
is of typeC
whereC
overloadsoperator->()
,x->y
gets expanded tox.operator->()->y
. - ^Meyers, Scott (October 1999), "Implementing operator->* for Smart Pointers"(PDF), Dr. Dobb's Journal, Aristeia.
- ^Although a
::
punctuator exists in C as of C23, it is not used as a scope resolution operator. - ^About C++11 User-defined literals
- ^ abcdefgsince C++11
- ^The parentheses are not necessary when taking the size of a value, only when taking the size of a type. However, they are usually used regardless.[citation needed]
- ^C++ defines
alignof
operator, whereas C defines_Alignof
(C23 defines both). Both operators have the same semantics. - ^Behaves like const_cast/static_cast/reinterpret_cast. In the last two cases, the
auto
specifier is replaced with the type of the invented variable x declared withauto x(a);
(which is never interpreted as a function declaration) orauto x{a};
, respectively. - ^For user-defined conversions, the return type implicitly and necessarily matches the operator name unless the type is inferred (e.g.
operatorauto()
,operatordecltype(auto)()
etc.). - ^The type name can also be inferred (e.g
new auto
) if an initializer is provided. - ^The array size can also be inferred if an initializer is provided.
See also
[edit]- Bitwise operations in C – Operations transforming individual bits of integral data types
- Bit manipulation – Algorithmically modifying data below the word level
- Logical operator – Symbol connecting sentential formulas in logic
- Boolean algebra (logic) – Algebraic manipulation of "true" and "false"
- Table of logic symbols – List of symbols used to express logical relations
References
[edit]- ^"Operator overloading§Comparison operators". cppreference.com.
- ^"Standard C++".
- ^ ab"Integers implementation", GCC 4.3.3, GNU.
- ^"ISO/IEC 9899:1999 specification, TC3"(PDF). p. 64, § 6.4.6 Ponctuators para. 3.
- ^"user-defined conversion". Retrieved 5 April 2020.
- ^Explicit type conversion in C++
- ^ISO/IEC 14882:1998(E) Programming Language C++. open-std.org – The C++ Standards Committee. 1 September 1998. pp. 40–41.
- ^ISO/IEC 9899:201x Programming Languages - C. open-std.org – The C Standards Committee. 19 December 2011. p. 465.
- ^the ISO C 1999 standard, section 6.5.6 note 71 (Technical report). ISO. 1999.
- ^"C++ Built-in Operators, Precedence and Associativity". docs.microsoft.com. Retrieved 11 May 2020.
- ^"C Operator Precedence - cppreference.com". en.cppreference.com. Retrieved 10 April 2020.
- ^"Does the C/C++ ternary operator actually have the same precedence as assignment operators?". Stack Overflow. Retrieved 22 September 2019.
- ^"Other operators - cppreference.com". en.cppreference.com. Retrieved 10 April 2020.
- ^"c++ - How does the Comma Operator work". Stack Overflow. Retrieved 1 April 2020.
- ^C history § Neonatal C, Bell labs.
- ^"Re^10: next unless condition". www.perlmonks.org. Retrieved 23 March 2018.
External links
[edit]- "Operators", C++ reference (wiki).
- C Operator Precedence
- Postfix Increment and Decrement Operators: ++ and -- (Developer network), Microsoft, 17 August 2021.