Operators in C and C++: Difference between revisions

Content deleted Content added
Expression evaluation order: order is backwards from precedence
m Relational: Fixed table spanning incorrectly.
 
(5 intermediate revisions by 3 users not shown)
Line 9:
 
Most of the operators available in C and C++ are also available in other [[C-family]] languages such as [[C Sharp (programming language)|C#]], [[D (programming language)|D]], [[Java (programming language)|Java]], [[Perl]], and [[PHP]] with the same precedence, associativity, and semantics.
 
Many ofoperators thespecified operatorsby containinga multi-charactersequence sequencesof symbols are givencommonly "names"referred builtto fromby thea operatorname that consists of the name of each charactersymbol. 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==
Line 67 ⟶ 69:
| {{rh}} colspan="2" | Postfix increment
| align="center" | <code>a'''++'''</code>
| {{cpp|1=R K::operator ++(int);}} {{efn|name=dummy-int|The {{cpp|int}} is a dummy parameter to differentiate between prefix and postfix.}}
| {{cpp|1=R operator ++(K& a, int);}} {{efn|name=dummy-int}}
|-
| {{rh}} colspan="2" | Prefix [[Increment and decrement operators|decrement]]
Line 77 ⟶ 79:
| {{rh}} colspan="2" | Postfix decrement
| align="center" | <code>a'''--'''</code>
| {{cpp|1=R K::operator --(int);}} {{efn|name=dummy-int}}
| {{cpp|1=R operator --(K& a, int);}} {{efn|name=dummy-int}}
|}
 
Line 126 ⟶ 128:
|-
| {{rh}} colspan="2" | [[Three-way comparison]]<ref name="threewaycomparison" group="lower-alpha"/>{{efn|Possible return types: <code>std::weak_ordering</code>, <code>std::strong_ordering</code> and <code>std::partial_ordering</code> to which they all are convertible to.}}
| rowspan="2" style="text-align:center;" | <code>a '''&lt;=&gt;''' b</code> || rowspan="2"{{no}}
| {{cpp|1=auto K::operator <=>(const S &b);}}
| {{cpp|1=auto operator <=>(const K &a, const S &b);}}
Line 173 ⟶ 175:
! outside class
|-
| {{rh}} colspan="2" | [[Bitwise operation#NOT|Bitwise NOT]]
| align="center" | <code>'''~'''a</code><br/>
| {{cpp|1=R K::operator ~();}}
| {{cpp|1=R operator ~(K a);}}
|-
| {{rh}} colspan="2" | [[Bitwise operation#AND|Bitwise AND]]
| style="text-align:center;" | <code>a '''&''' b</code>
| {{cpp|1=R K::operator &(S b);}}
| {{cpp|1=R operator &(K a, S b);}}
|-
| {{rh}} colspan="2" | [[Bitwise operation#OR|Bitwise OR]]
| style="text-align:center;" | <code>a '''<nowiki>|</nowiki>''' b</code>
| {{cpp|1=R K::operator {{!}}(S b);|lang=cpp}}
| {{cpp|1=R operator {{!}}(K a, S b);|lang=cpp}}
|-
| {{rh}} colspan="2" | [[Bitwise operation#XOR|Bitwise XOR]]
| style="text-align:center;" | <code>a '''^''' b</code>
| {{cpp|1=R K::operator ^(S b);}}
| {{cpp|1=R operator ^(K a, S b);}}
|-
| {{rh}} colspan="2" | [[Bitwise shift|BitwiseShift]] left shift]]<ref name="bitshift" group="lower-alpha" />
| style="text-align:center;" | <code>a '''<<''' b</code>
| {{cpp|1=R K::operator <<(S b);}}
| {{cpp|1=R operator <<(K a, S b);}}
|-
| {{rh}} colspan="2" | [[Bitwise shift|BitwiseShift right shift]]<ref name="bitshift" group="lower-alpha" />{{Refn | Operation="rightbitshift" | group="lower-alpha" | According to the C99 standard, the right shift of a negative number is implementation defined. Most implementations, e.g., the GCC,<ref name="Integers">{{Citation | contribution = Integers implementation | url = //gcc.gnu.org/onlinedocs/gcc-4.3.3/gcc/Integers-implementation.html#Integers-implementation | title = GCC 4.3.3 | publisher = GNU}}.</ref> use an [[arithmetic shift]] (i.e., sign extension), but a [[logical shift]] is possible.}}
| style="text-align:center;" | <code>a '''>>''' b</code>
| {{cpp|1=R K::operator >>(S b);}}
Line 208 ⟶ 210:
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> represnetsrepresents an operation) is equivalent to <code>a = a ⊚ b</code>, except that <code>a</code> is evaluated only once.
 
{| class="wikitable" style="width:100%"
Line 382 ⟶ 384:
| {{n/a}}
|-
| {{rh}} colspan="2" | [[type conversion|Conversion]] {{efn|Behaves like const_cast/static_cast/reinterpret_cast. In the last two cases, the <code>auto</code> specifier is replaced with the type of the invented variable x declared with <code>auto x(a);</code> (which is never interpreted as a function declaration) or <code>auto x{a};</code>, respectively.}}<ref>[https://en.cppreference.com/w/cpp/language/explicit_cast Explicit type conversion] in C++</ref>
| style="text-align:center;" | <code>R(a)</code><br><code>R{a}</code><ref name="sinceCXX11" group="lower-alpha" /><br><code>auto(a)</code><ref name="sinceCXX23" group="lower-alpha" /><br><code>auto{a}</code><ref name="sinceCXX23" group="lower-alpha" /> || {{no}} || {{no}}
| {{rh}} colspan="2" {{n/a}}
|-
| {{rh}} colspan="2" | [[static_cast]] conversion {{efn|For user-defined conversions, the return type implicitly and necessarily matches the operator name unless the type is inferred (e.g. {{cpp|1=operator auto()}}, {{cpp|1=operator decltype(auto)()}} etc.).}}
| style="text-align:center;" | <code>'''static_cast'''<R>(a)</code> || {{yes}} || {{no}}
| {{cpp|1=K::operator R();}}<br>{{cpp|1=explicit K::operator R();}}<ref name="sinceCXX11" group="lower-alpha" />
Line 696 ⟶ 698:
|}
 
===NotesDetails===
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: {{mono|x}} is 'bound' more tightly to {{mono|++}} than to {{mono|*}}, so that whatever {{mono|++}} does (now or later—see below), it does it ONLY to {{mono|x}} (and not to <code>x*3</code>); it is equivalent to (<code>++x</code>, <code>x*3</code>).
Line 705 ⟶ 708:
* 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===
Many of the operators containing multi-character sequences are given "names" built from the operator name of each character. 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".
The binding of operators in C and C++ is specified (in the corresponding Standards) 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:
Line 718 ⟶ 721:
which is a valid expression.<ref>{{cite web |title=C Operator Precedence - cppreference.com |url=https://en.cppreference.com/w/c/language/operator_precedence |website=en.cppreference.com |access-date=10 April 2020}}</ref><ref>{{Cite web|url=https://stackoverflow.com/questions/13515434/does-the-c-c-ternary-operator-actually-have-the-same-precedence-as-assignment/13515505|title=Does the C/C++ ternary operator actually have the same precedence as assignment operators?|website=Stack Overflow|access-date=2019-09-22}}</ref>
 
IfTo youuse wantthe tocomma use comma-as-operator withinin a single function call argument expression, variable assignment, or othera comma-separated list, youuse needof toparentheses useis parentheses,required.<ref>{{cite web |title=Other operators - cppreference.com |url=https://en.cppreference.com/w/c/language/operator_other |website=en.cppreference.com |access-date=10 April 2020}}</ref><ref>{{cite web |title=c++ - How does the Comma Operator work |url=https://stackoverflow.com/questions/54142/how-does-the-comma-operator-work/ |website=Stack Overflow |access-date=1 April 2020}}</ref> e.g.:For example,

<syntaxhighlight lang="cpp">
int a = 1, b = 2, weirdVariable = (++a, b), d = 4;
</syntaxhighlight>
 
===Criticism of bitwise and equality operators precedence===