Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does multiple assignment (a = b) = c syntax work? [closed]

Tags:

c++

operators

How does a statement like (a = b) = c; work in C++, assuming a,b and c are ints or any other primitive type?

like image 965
imadhsissou Avatar asked Sep 18 '16 15:09

imadhsissou


People also ask

What is the syntax of multiple assignment in C?

MultipleAssignment is a language property of being able to assign one value to more than one variables. It usually looks like the following: a = b = c = d = 0 // assigns all variables to 0.

What is the syntax of assignment operator How does it work?

The assignment operators return the value of the object specified by the left operand after the assignment. The resultant type is the type of the left operand. The result of an assignment expression is always an l-value. These operators have right-to-left associativity.

How does assignment work in C?

An assignment operation assigns the value of the right-hand operand to the storage location named by the left-hand operand. Therefore, the left-hand operand of an assignment operation must be a modifiable l-value. After the assignment, an assignment expression has the value of the left operand but is not an l-value.

How many types of assignments are there in C?

We have 2 types of Assignment Operators in C : Simple Assignment operator (Example : = ). Compound Assignment Operators (Example : =+ , -= , & = ).


2 Answers

The assignment expression a = b is not an lvalue in C, but it is in C++:

  • C11, 6.5.14 (Assignment operators):

    An assignment operator stores a value in the object designated by the left operand. An assignment expression has the value of the left operand after the assignment, but is not an lvalue.

  • C++14, 5.18 [expr.ass] (Assignment and compound assignment operators):

    The assignment operator (=) and the compound assignment operators all group right-to-left. All require a modifiable lvalue as their left operand and return an lvalue referring to the left operand.

In the evolution of C++ from C, several expressions were made "lvalue-aware", as it were, because lvalues are much more important in C++ than in C. In C, everything is trivial (trivially copyable and trivially destructible, all in the words of C++), so lvalue-to-rvalue conversions (or "lvalue conversions", as C calls them) aren't painful. In C++, copying and destruction are non-trivial concepts, and by making expressions preserve lvalue-ness, a lot of copying and destructing can be avoided that was never necessary to begin with.

Another example is the conditional expression (a ? b : c), which is not an lvalue in C, but can be a lvalue in C++.

Another interesting artefact of this language evolution is that C has four well-defined storage durations (automatic, static, thread-local, dynamic), but in C++ this becomes more muddled, since temporary objects are a non-trivial concept in C++ that almost calls for its own storage duration. (E.g. Clang internally has a fifth, "full expression" storage duration.) Temporaries are of course the result of lvalue-to-rvalue conversion, so by avoiding the conversion, there's one less thing to worry about.

(Please note that all of this discussion only applies to the respective core language expressions. C++ also has the separate, unrelated feature of operator overloading, which produces function call expressions, which have all the usual semantics of function calls and have nothing to do with operators except for the syntax. For example, you can define an overloaded operator= that returns a prvalue or void if you so wish.)

like image 182
Kerrek SB Avatar answered Oct 03 '22 07:10

Kerrek SB


Informally, in C++, for builtin types, the result of a = b is a reference to a; you can assign a value to that reference, just as with any other reference. So (a = b) = c assigns the value of b to a, and then assigns the value of c to a.

For user-defined types this may not apply, although the usual idiom is for an assignment operator to return a reference to the left-hand argument, so the behavior of user-defined types mimics the behavior of builtin types:

struct S {     S& operator=(const S& rhs) {         return *this;     } }; 

Now, S a, b, c; (a = b) = c; means call a.operator=(b), which returns a reference to a; then call S::operator= on that result and c, effectively calling a.operator=(c).

like image 36
Pete Becker Avatar answered Oct 03 '22 07:10

Pete Becker