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 <code>&&</code>, <code>||</code>, and <code>,</code> (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, <code>+=</code> and <code>-=</code> are often called "plus equal(s)" and "minus equal(s)", instead of the more verbose "assignment by addition" and "assignment by subtraction".
Operators
In the following tables, lower case letters such as <code>a</code> and <code>b</code> represent literal values, object/variable names, or l-values, as appropriate. <code>R</code>, <code>S</code> and <code>T</code> stand for a data type, and <code>K</code> for a class or enumeration type. Some operators have alternative spellings using digraphs and trigraphs or operator synonyms.
Arithmetic
C and C++ have the same arithmetic operators and all can be overloaded in C++.
{| class="wikitable" style="width:100%"
! colspan="2" rowspan="2" | Operation
! rowspan="2" | Syntax
! colspan="2" | C++ prototype
|-
! in class K
! outside class
|-
| colspan="2" | Addition
| align="center" |
|
|
|-
| colspan="2" | Subtraction
| align="center" | <code>a - b</code>
|
|
|-
| colspan="2" | Unary plus; integer promotion
|align="center" | <code>+a</code>
|
|
|-
| colspan="2" | Unary minus; additive inverse
| align="center" | <code>-a</code>
|
|
|-
| colspan="2" | Multiplication
| align="center" | <code>a * b</code>
|
|
|-
| colspan="2" | Division
| align="center" | <code>a / b</code>
|
|
|-
| colspan="2" | Modulo
{| class="wikitable" style="width:100%"
! colspan="2" rowspan="2" | Operation
! rowspan="2" | Syntax
! rowspan="2" | In C
! colspan="2" | C++ prototype
|-
! in class K
! outside class
|-
| colspan="2" | Equal to
| align="center" | <code>a == b</code>
|
|
|
|-
| colspan="2" | Not equal to
| style="text-align:center;" | <code>a != b</code> ||
|
|
|-
| colspan="2" | Greater than
| style="text-align:center;" | <code>a > b</code> ||
|
|
|-
| colspan="2" | Less than
| style="text-align:center;" | <code>a < b</code> ||
|
|
|-
| colspan="2" | Greater than or equal to
| style="text-align:center;" | <code>a >= b</code> ||
|
|
|-
| colspan="2" | Less than or equal to
| style="text-align:center;" | <code>a <= b</code> ||
|
|
|-
| colspan="2" | Three-way comparison
{| class="wikitable" style="width:100%"
! colspan="2" rowspan="2" | Operation
! rowspan="2" | Syntax
! colspan="2" | C++ prototype
|-
! in class K
! outside class
|-
| colspan="2" | NOT
| align="center" | <code>!a</code>
|
|
|-
| colspan="2" | AND
| style="text-align:center;" | <code>a && b</code>
|
|
|-
| colspan="2" | OR
| style="text-align:center;" | <code>a <nowiki>||</nowiki> b</code>
|
|
|}
Bitwise
C and C++ have the same bitwise operators and all can be overloaded in C++.
{| class="wikitable" style="width:100%"
! colspan="2" rowspan="2" | Operation
! rowspan="2" | Syntax
! colspan="2" | C++ prototype
|-
! in class K
! outside class
|-
| colspan="2" | NOT
| align="center" | <code>~a</code><br/>
|
|
|-
| colspan="2" | AND
| style="text-align:center;" | <code>a & b</code>
|
|
|-
| colspan="2" | OR
| style="text-align:center;" | <code>a <nowiki>|</nowiki> b</code>
|
|
|-
| colspan="2" | XOR
| style="text-align:center;" | <code>a ^ b</code>
|
|
|-
| colspan="2" | Shift left use an arithmetic shift (i.e., sign extension), but a logical shift is possible.
| style="text-align:center;" | <code>a >> b</code>
|
|
|}
Assignment
C and C++ have the same assignment operators and all can be overloaded in C++.
For the combination operators, <code>a ⊚= b</code> (where <code>⊚</code> represents an operation) is equivalent to <code>a = a ⊚ b</code>, except that <code>a</code> is evaluated only once.
{| class="wikitable" style="width:100%"
! rowspan="2" | Operation
! rowspan="2" | Syntax
! colspan="2" | C++ prototype
|-
! in class K
! outside class
|-
! | Assignment
| style="text-align:center;" |
|
|
|-
! | Addition combination
| align="center" | <code>a += b</code>
|
|
|-
! | Subtraction combination
| style="text-align:center;" | <code>a -= b</code>
|
|
|-
! | Multiplication combination
| style="text-align:center;" | <code>a *= b</code>
|
|
|-
! | Division combination
| style="text-align:center;" | <code>a /= b</code>
|
|
|-
! | Modulo combination
| style="text-align:center;" | <code>a %= b</code>
|
|
|-
! | Bitwise AND combination
| style="text-align:center;" | <code>a &= b</code>
|
|
|-
! | Bitwise OR combination
| style="text-align:center;" | <code>a <nowiki>|</nowiki>= b</code>
|
|
|-
! | Bitwise XOR combination
| style="text-align:center;" | <code>a ^= b</code>
|
|
|-
! | Bitwise left shift combination
| style="text-align:center;" | <code>a <<= b</code>
|
|
|-
! | Bitwise right shift combination
| style="text-align:center;" | <code>a >>= b</code>
|
|
|}
Member and pointer
{| class="wikitable" style="width:100%"
! colspan="2" rowspan="2" | Operation
! rowspan="2" | Syntax
! rowspan="2" | Can overload
! rowspan="2" | In C
! colspan="2" | C++ prototype
|-
! in class K
! outside class
|-
| colspan="2" | Subscript
| align="center" | <code>a[b]</code><code>a<:b:></code>
|
|
| <br/>
|
|-
| colspan="2" | Conversion
| style="text-align:center;" | <code>R(a)</code><br><code>R{a}</code>
{| class="wikitable" style="width:30%; text-align:center;"
! Keyword || Operator
|-
| || <code>&&</code>
|-
| || <code>&=</code>
|-
| || <code>&</code>
|-
| || <code>|</code>
|-
| || <code>~</code>
|-
| || <code>!</code>
|-
| || <code>!=</code>
|-
| || <code>||</code>
|-
| || <code>|=</code>
|-
| || <code>^</code>
|-
| || <code>^=</code>
|}
Each keyword is a different way to specify an operator and as such can be used instead of the corresponding symbolic variation. For example, and specify the same behavior. As another example, the <code>bitand</code> 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., ).
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 , 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
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).
Operator precedence is not affected by overloading.
{| class="wikitable"
|-
! style="text-align: left" | Order
! style="text-align: left" | Operator
! style="text-align: left" | Description
! style="text-align: left" | Associativity
|-
! 1
<small>highest</small>
| <code>::</code>
| Scope resolution (C++ only)
| None
|-
! rowspan=11| 2
| style="border-bottom-style: none" | <code>++</code>
| style="border-bottom-style: none" | Postfix increment
| style="vertical-align: top" rowspan="11" | Left-to-right
|-
| style="border-bottom-style: none; border-top-style: none" | <code>--</code>
| style="border-bottom-style: none; border-top-style: none" | Postfix decrement
|-
| style="border-bottom-style: none; border-top-style: none" | <code>()</code>
| style="border-bottom-style: none; border-top-style: none" | Function call
|-
| style="border-bottom-style: none; border-top-style: none" | <code>[]</code>
| style="border-bottom-style: none; border-top-style: none" | Array subscripting
|-
| style="border-bottom-style: none; border-top-style: none" | <code>.</code>
| style="border-bottom-style: none; border-top-style: none" | Element selection by reference
|-
| style="border-bottom-style: none; border-top-style: none" | <code>-></code>
| style="border-bottom-style: none; border-top-style: none" | Element selection through pointer
|-
| style="border-bottom-style: none; border-top-style: none" | <code>typeid()</code>
| style="border-bottom-style: none; border-top-style: none" | Run-time type information (C++ only) (see typeid)
|-
| style="border-bottom-style: none; border-top-style: none" | <code>const_cast</code>
| style="border-bottom-style: none; border-top-style: none" | Type cast (C++ only) (see const_cast)
|-
| style="border-bottom-style: none; border-top-style: none" | <code>dynamic_cast</code>
| style="border-bottom-style: none; border-top-style: none" | Type cast (C++ only) (see dynamic cast)
|-
| style="border-bottom-style: none; border-top-style: none" | <code>reinterpret_cast</code>
| style="border-bottom-style: none; border-top-style: none" | Type cast (C++ only) (see reinterpret_cast)
|-
| style="border-top-style: none" | <code>static_cast</code>
| style="border-top-style: none" | Type cast (C++ only) (see static_cast)
|-
! rowspan="13" | 3
| style="border-bottom-style: none" | <code>++</code>
| style="border-bottom-style: none" | Prefix increment
| rowspan="13" style="vertical-align: top" | Right-to-left
|-
| style="border-bottom-style: none; border-top-style: none" | <code>--</code>
| style="border-bottom-style: none; border-top-style: none" | Prefix decrement
|-
| style="border-bottom-style: none; border-top-style: none" | <code>+</code>
| style="border-bottom-style: none; border-top-style: none" | Unary plus
|-
| style="border-bottom-style: none; border-top-style: none" | <code>-</code>
| style="border-bottom-style: none; border-top-style: none" | Unary minus
|-
| style="border-bottom-style: none; border-top-style: none" | <code>!</code>
| style="border-bottom-style: none; border-top-style: none" | Logical NOT
|-
| style="border-bottom-style: none; border-top-style: none" | <code>~</code>
| style="border-bottom-style: none; border-top-style: none" | Bitwise NOT (ones' complement)
|-
| style="border-bottom-style: none; border-top-style: none" | <code>(type)</code>
| style="border-bottom-style: none; border-top-style: none" | Type cast
|-
| style="border-bottom-style: none; border-top-style: none" | <code>*</code>
| style="border-bottom-style: none; border-top-style: none" | Indirection (dereference)
|-
| style="border-bottom-style: none; border-top-style: none" | <code>&</code>
| style="border-bottom-style: none; border-top-style: none" | Address-of
|-
| style="border-bottom-style: none; border-top-style: none" | <code>sizeof</code>
| style="border-bottom-style: none; border-top-style: none" | Sizeof
|-
| style="border-bottom-style: none; border-top-style: none" | <code>_Alignof</code>
| style="border-bottom-style: none; border-top-style: none" | Alignment requirement (since C11)
|-
| style="border-bottom-style: none; border-top-style: none" | <code>new</code>, <code>new[]</code>
| style="border-bottom-style: none; border-top-style: none" | Dynamic memory allocation (C++ only)
|-
| style="border-top-style: none" | <code>delete</code>, <code>delete[]</code>
| style="border-top-style: none" | Dynamic memory deallocation (C++ only)
|-
! rowspan=2| 4
| style="border-bottom-style: none" | <code>.*</code>
| style="border-bottom-style: none" | Pointer to member (C++ only)
| style="vertical-align: top" rowspan="2" | Left-to-right
|-
| style="border-bottom-style: none; border-top-style: none" | <code>->*</code>
| style="border-bottom-style: none; border-top-style: none" | Pointer to member (C++ only)
|-
! rowspan=3| 5
| style="border-bottom-style: none" | <code>*</code>
| style="border-bottom-style: none" | Multiplication
| style="vertical-align: top" rowspan="3" | Left-to-right
|-
| style="border-bottom-style: none; border-top-style: none" | <code>/</code>
| style="border-bottom-style: none; border-top-style: none" | Division
|-
| style="border-bottom-style: none; border-top-style: none" | <code>%</code>
| style="border-bottom-style: none; border-top-style: none" | Modulo (remainder)
|-
! rowspan=2| 6
| style="border-bottom-style: none" | <code>+</code>
| style="border-bottom-style: none" | Addition
| style="vertical-align: top" rowspan="2" | Left-to-right
|-
| style="border-bottom-style: none; border-top-style: none" | <code>-</code>
| style="border-bottom-style: none; border-top-style: none" | Subtraction
|-
! rowspan=2| 7
| style="border-bottom-style: none" | <code><<</code>
| style="border-bottom-style: none" | Bitwise left shift
| style="vertical-align: top" rowspan="2" | Left-to-right
|-
| style="border-bottom-style: none; border-top-style: none" | <code>>></code>
| style="border-bottom-style: none; border-top-style: none" | Bitwise right shift
|-
! rowspan=1| 8
| style="border-bottom-style:none;" | <code><=></code>
| style="border-bottom-style:none;" | Three-way comparison (Introduced in C++20 - C++ only)
| style="vertical-align: top" rowspan="1" | Left-to-right
|-
! rowspan=4| 9
| style="border-bottom-style: none" | <code><</code>
| style="border-bottom-style: none" | Less than
| style="vertical-align: top" rowspan="4" | Left-to-right
|-
| style="border-bottom-style: none; border-top-style: none" | <code><=</code>
| style="border-bottom-style: none; border-top-style: none" | Less than or equal to
|-
| style="border-bottom-style: none; border-top-style: none" | <code>></code>
| style="border-bottom-style: none; border-top-style: none" | Greater than
|-
| style="border-bottom-style: none; border-top-style: none" | <code>>=</code>
| style="border-bottom-style: none; border-top-style: none" | Greater than or equal to
|-
! rowspan=2| 10
| style="border-bottom-style: none" | <code>==</code>
| style="border-bottom-style: none" | Equal to
| style="vertical-align: top" rowspan="2" | Left-to-right
|-
| style="border-bottom-style: none; border-top-style: none" | <code>!=</code>
| style="border-bottom-style: none; border-top-style: none" | Not equal to
|-
! 11
| <code>&</code>
| Bitwise AND
| Left-to-right
|-
! 12
| <code>^</code>
| Bitwise XOR (exclusive or)
| Left-to-right
|-
! 13
| <code><nowiki>|</nowiki></code>
| Bitwise OR (inclusive or)
| Left-to-right
|-
! 14
| <code>&&</code>
| Logical AND
| Left-to-right
|-
! 15
| <code><nowiki>||</nowiki></code>
| Logical OR
| Left-to-right
|-
! rowspan="2" | 16
| style="border-bottom-style: none" | <code>co_await</code>
| rowspan="2" | Coroutine processing (C++ only)
| rowspan="2" | Right-to-left
|-
| style="border-top-style: none" | <code>co_yield</code>
|-
! rowspan="13" | 17
| style="border-bottom-style: none" | <code>?:</code>
| style="border-bottom-style: none" | Ternary conditional operator
| rowspan="13" | Right-to-left
|-
| style="border-bottom-style: none; border-top-style: none" | <code>=</code>
| style="border-bottom-style: none; border-top-style: none" | Direct assignment
|-
| style="border-bottom-style: none; border-top-style: none" | <code>+=</code>
| style="border-bottom-style: none; border-top-style: none" | Assignment by sum
|-
| style="border-bottom-style: none; border-top-style: none" | <code>-=</code>
| style="border-bottom-style: none; border-top-style: none" | Assignment by difference
|-
| style="border-bottom-style: none; border-top-style: none" | <code>*=</code>
| style="border-bottom-style: none; border-top-style: none" | Assignment by product
|-
| style="border-bottom-style: none; border-top-style: none" | <code>/=</code>
| style="border-bottom-style: none; border-top-style: none" | Assignment by quotient
|-
| style="border-bottom-style: none; border-top-style: none" | <code>%=</code>
| style="border-bottom-style: none; border-top-style: none" | Assignment by remainder
|-
| style="border-bottom-style: none; border-top-style: none" | <code><<=</code>
| style="border-bottom-style: none; border-top-style: none" | Assignment by bitwise left shift
|-
| style="border-bottom-style: none; border-top-style: none" | <code>>>=</code>
| style="border-bottom-style: none; border-top-style: none" | Assignment by bitwise right shift
|-
| style="border-bottom-style: none; border-top-style: none" | <code>&=</code>
| style="border-bottom-style: none; border-top-style: none" | Assignment by bitwise AND
|-
| style="border-bottom-style: none; border-top-style: none" | <code>^=</code>
| style="border-bottom-style: none; border-top-style: none" | Assignment by bitwise XOR
|-
| style="border-bottom-style: none; border-top-style: none" | <code><nowiki>|</nowiki>=</code>
| style="border-bottom-style: none; border-top-style: none" | Assignment by bitwise OR
|-
| style="border-top-style: none" | <code>throw</code>
| style="border-top-style: none" | Throw operator (exceptions throwing, C++ only)
|-
! 18
<small>lowest</small>
| <code>,</code>
| Comma
| Left-to-right
|}
Details
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 <code>a ? b, c : d</code> is interpreted as <code>a ? (b, c) : d</code>, and not as the meaningless <code>(a ? b), (c : d)</code>. So, the expression in the middle of the conditional operator (between <code>?</code> and <code>:</code>) is parsed as if parenthesized. Also, the immediate, un-parenthesized result of a C cast expression cannot be the operand of <code>sizeof</code>. Therefore, <code>sizeof (int) * x</code> is interpreted as <code>(sizeof(int)) * x</code> and not <code>sizeof ((int) * x)</code>.
Chained expressions
The precedence table determines the order of binding in chained expressions, when it is not expressly specified by parentheses.
- For example, <code>++x*3</code> is ambiguous without some precedence rule(s). The precedence table tells us that: is 'bound' more tightly to than to , so that whatever does (now or later—see below), it does it ONLY to (and not to <code>x*3</code>); it is equivalent to (<code>++x</code>, <code>x*3</code>).
- Similarly, with <code>3*x++</code>, where though the post-fix is designed to act AFTER the entire expression is evaluated, the precedence table makes it clear that ONLY gets incremented (and NOT <code>3*x</code>). In fact, the expression (<code>tmp=x++</code>, <code>3*tmp</code>) is evaluated with being a temporary value. It is functionally equivalent to something like (<code>tmp=3*x</code>, <code>++x</code>, <code>tmp</code>).
center|thumb|Precedence and bindings
- 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])++). 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
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:
<syntaxhighlight lang="c">logical-OR-expression ? expression : conditional-expression</syntaxhighlight>
while in C++ it is:
<syntaxhighlight lang="cpp">logical-OR-expression ? expression : assignment-expression</syntaxhighlight>
Hence, the expression:
<syntaxhighlight lang="text">e = a < d ? a++ : a = d</syntaxhighlight>
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:
<syntaxhighlight lang="c">unary-expression '=' assignment-expression</syntaxhighlight>
In C++, it is parsed as:
<syntaxhighlight lang="cpp">e = (a < d ? a++ : (a = d))</syntaxhighlight>
which is a valid expression.
To use the comma operator in a function call argument expression, variable assignment, or a comma-separated list, use of parentheses is required. For example,
<syntaxhighlight lang="cpp">
int a = 1, b = 2, weirdVariable = (++a, b), d = 4;
</syntaxhighlight>
Criticism of bitwise and equality operators precedence
The precedence of the bitwise logical operators has been criticized. Conceptually, & and | are arithmetic operators like * and +.
The expression is syntactically parsed as whereas the expression is parsed as . 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 it behaved as a logical operator, but in it behaved as a bitwise one). It was retained so as to keep backward compatibility with existing installations.
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
See also
References
External links
- .
- C Operator Precedence
- .
