- C Data Types
- C Operators
- C Input and Output
- C Control Flow
- C Functions
- C Preprocessors
- C File Handling
- C Cheatsheet
- C Interview Questions
lvalue and rvalue in C language
Lvalue:- .
lvalue simply means an object that has an identifiable location in memory (i.e. having an address).
- In any assignment statement “lvalue” must have the capability to store the data.
- lvalue cannot be a function, expression (like a+b) or a constant (like 3 , 4 , etc.).
L-value : “l-value” refers to memory location which identifies an object. l-value may appear as either left hand or right hand side of an assignment operator(=). l-value often represents as identifier. Expressions referring to modifiable locations are called “ modifiable l-values “. A modifiable l-value cannot have an array type, an incomplete type, or a type with the const attribute. For structures and unions to be modifiable lvalues , they must not have any members with the const attribute. The name of the identifier denotes a storage location, while the value of the variable is the value stored at that location. An identifier is a modifiable lvalue if it refers to a memory location and if its type is arithmetic, structure, union or pointer. For example, if ptr is a pointer to a storage region, then *ptr is a modifiable l-value that designates the storage region to which ptr points. In C, the concept was renamed as “locator value” , and referred to expressions that locate (designate) objects. The l-value is one of the following:
- The name of the variable of any type i.e. , an identifier of integral, floating, pointer, structure, or union type.
- A subscript ([ ]) expression that does not evaluate to an array.
- A unary-indirection (*) expression that does not refer to an array
- An l-value expression in parentheses.
- A const object (a nonmodifiable l-value).
- The result of indirection through a pointer, provided that it isn’t a function pointer.
- The result of member access through pointer(-> or .)
p = &a; // ok, assignment of address // at l-value
&a = p; // error: &a is an r-value
( x < y ? y : x) = 0; // It’s valid because the ternary // expression preserves the "lvalue-ness" // of both its possible return values
r-value simply means, an object that has no identifiable location in memory (i.e. having an address).
- Anything that is capable of returning a constant expression or value.
- Expression like a+b will return some constant.
R-value : r-value” refers to data value that is stored at some address in memory. A r-value is an expression, that can’t have a value assigned to it, which means r-value can appear on right but not on left hand side of an assignment operator(=).
Note : The unary & (address-of) operator requires an l-value as its operand. That is, &n is a valid expression only if n is an l-value. Thus, an expression such as &12 is an error. Again, 12 does not refer to an object, so it’s not addressable. For instance,
Remembering the mnemonic, that l-values can appear on the left of an assignment operator while r-values can appear on the right.
Reference: https://msdn.microsoft.com/en-us/library/bkbs2cds.aspx
Similar Reads
Improve your coding skills with practice.
What kind of Experience do you want to share?
Next: Execution Control Expressions , Previous: Arithmetic , Up: Top [ Contents ][ Index ]
7 Assignment Expressions
As a general concept in programming, an assignment is a construct that stores a new value into a place where values can be stored—for instance, in a variable. Such places are called lvalues (see Lvalues ) because they are locations that hold a value.
An assignment in C is an expression because it has a value; we call it an assignment expression . A simple assignment looks like
We say it assigns the value of the expression value-to-store to the location lvalue , or that it stores value-to-store there. You can think of the “l” in “lvalue” as standing for “left,” since that’s what you put on the left side of the assignment operator.
However, that’s not the only way to use an lvalue, and not all lvalues can be assigned to. To use the lvalue in the left side of an assignment, it has to be modifiable . In C, that means it was not declared with the type qualifier const (see const ).
The value of the assignment expression is that of lvalue after the new value is stored in it. This means you can use an assignment inside other expressions. Assignment operators are right-associative so that
is equivalent to
This is the only useful way for them to associate; the other way,
would be invalid since an assignment expression such as x = y is not valid as an lvalue.
Warning: Write parentheses around an assignment if you nest it inside another expression, unless that is a conditional expression, or comma-separated series, or another assignment.
Understanding lvalues and rvalues in C and C++
The terms lvalue and rvalue are not something one runs into often in C/C++ programming, but when one does, it's usually not immediately clear what they mean. The most common place to run into these terms are in compiler error & warning messages. For example, compiling the following with gcc :
True, this code is somewhat perverse and not something you'd write, but the error message mentions lvalue , which is not a term one usually finds in C/C++ tutorials. Another example is compiling this code with g++ :
Now the error is:
Here again, the error mentions some mysterious rvalue . So what do lvalue and rvalue mean in C and C++? This is what I intend to explore in this article.
A simple definition
This section presents an intentionally simplified definition of lvalues and rvalues . The rest of the article will elaborate on this definition.
An lvalue ( locator value ) represents an object that occupies some identifiable location in memory (i.e. has an address).
rvalues are defined by exclusion, by saying that every expression is either an lvalue or an rvalue . Therefore, from the above definition of lvalue , an rvalue is an expression that does not represent an object occupying some identifiable location in memory.
Basic examples
The terms as defined above may appear vague, which is why it's important to see some simple examples right away.
Let's assume we have an integer variable defined and assigned to:
An assignment expects an lvalue as its left operand, and var is an lvalue, because it is an object with an identifiable memory location. On the other hand, the following are invalid:
Neither the constant 4 , nor the expression var + 1 are lvalues (which makes them rvalues). They're not lvalues because both are temporary results of expressions, which don't have an identifiable memory location (i.e. they can just reside in some temporary register for the duration of the computation). Therefore, assigning to them makes no semantic sense - there's nowhere to assign to.
So it should now be clear what the error message in the first code snippet means. foo returns a temporary value which is an rvalue. Attempting to assign to it is an error, so when seeing foo() = 2; the compiler complains that it expected to see an lvalue on the left-hand-side of the assignment statement.
Not all assignments to results of function calls are invalid, however. For example, C++ references make this possible:
Here foo returns a reference, which is an lvalue , so it can be assigned to. Actually, the ability of C++ to return lvalues from functions is important for implementing some overloaded operators. One common example is overloading the brackets operator [] in classes that implement some kind of lookup access. std::map does this:
The assignment mymap[10] works because the non-const overload of std::map::operator[] returns a reference that can be assigned to.
Modifiable lvalues
Initially when lvalues were defined for C, it literally meant "values suitable for left-hand-side of assignment". Later, however, when ISO C added the const keyword, this definition had to be refined. After all:
So a further refinement had to be added. Not all lvalues can be assigned to. Those that can are called modifiable lvalues . Formally, the C99 standard defines modifiable lvalues as:
[...] an lvalue that does not have array type, does not have an incomplete type, does not have a const-qualified type, and if it is a structure or union, does not have any member (including, recursively, any member or element of all contained aggregates or unions) with a const-qualified type.
Conversions between lvalues and rvalues
Generally speaking, language constructs operating on object values require rvalues as arguments. For example, the binary addition operator '+' takes two rvalues as arguments and returns an rvalue:
As we've seen earlier, a and b are both lvalues. Therefore, in the third line, they undergo an implicit lvalue-to-rvalue conversion . All lvalues that aren't arrays, functions or of incomplete types can be converted thus to rvalues.
What about the other direction? Can rvalues be converted to lvalues? Of course not! This would violate the very nature of an lvalue according to its definition [1] .
This doesn't mean that lvalues can't be produced from rvalues by more explicit means. For example, the unary '*' (dereference) operator takes an rvalue argument but produces an lvalue as a result. Consider this valid code:
Conversely, the unary address-of operator '&' takes an lvalue argument and produces an rvalue:
The ampersand plays another role in C++ - it allows to define reference types. These are called "lvalue references". Non-const lvalue references cannot be assigned rvalues, since that would require an invalid rvalue-to-lvalue conversion:
Constant lvalue references can be assigned rvalues. Since they're constant, the value can't be modified through the reference and hence there's no problem of modifying an rvalue. This makes possible the very common C++ idiom of accepting values by constant references into functions, which avoids unnecessary copying and construction of temporary objects.
CV-qualified rvalues
If we read carefully the portion of the C++ standard discussing lvalue-to-rvalue conversions [2] , we notice it says:
An lvalue (3.10) of a non-function, non-array type T can be converted to an rvalue. [...] If T is a non-class type, the type of the rvalue is the cv-unqualified version of T. Otherwise, the type of the rvalue is T.
What is this "cv-unqualified" thing? CV-qualifier is a term used to describe const and volatile type qualifiers.
From section 3.9.3:
Each type which is a cv-unqualified complete or incomplete object type or is void (3.9) has three corresponding cv-qualified versions of its type: a const-qualified version, a volatile-qualified version, and a const-volatile-qualified version. [...] The cv-qualified or cv-unqualified versions of a type are distinct types; however, they shall have the same representation and alignment requirements (3.9)
But what has this got to do with rvalues? Well, in C, rvalues never have cv-qualified types. Only lvalues do. In C++, on the other hand, class rvalues can have cv-qualified types, but built-in types (like int ) can't. Consider this example:
The second call in main actually calls the foo () const method of A , because the type returned by cbar is const A , which is distinct from A . This is exactly what's meant by the last sentence in the quote mentioned earlier. Note also that the return value from cbar is an rvalue. So this is an example of a cv-qualified rvalue in action.
Rvalue references (C++11)
Rvalue references and the related concept of move semantics is one of the most powerful new features the C++11 standard introduces to the language. A full discussion of the feature is way beyond the scope of this humble article [3] , but I still want to provide a simple example, because I think it's a good place to demonstrate how an understanding of what lvalues and rvalues are aids our ability to reason about non-trivial language concepts.
I've just spent a good part of this article explaining that one of the main differences between lvalues and rvalues is that lvalues can be modified, and rvalues can't. Well, C++11 adds a crucial twist to this distinction, by allowing us to have references to rvalues and thus modify them, in some special circumstances.
As an example, consider a simplistic implementation of a dynamic "integer vector". I'm showing just the relevant methods here:
So, we have the usual constructor, destructor, copy constructor and copy assignment operator [4] defined, all using a logging function to let us know when they're actually called.
Let's run some simple code, which copies the contents of v1 into v2 :
What this prints is:
Makes sense - this faithfully represents what's going on inside operator= . But suppose that we want to assign some rvalue to v2 :
Although here I just assign a freshly constructed vector, it's just a demonstration of a more general case where some temporary rvalue is being built and then assigned to v2 (this can happen for some function returning a vector, for example). What gets printed now is this:
Ouch, this looks like a lot of work. In particular, it has one extra pair of constructor/destructor calls to create and then destroy the temporary object. And this is a shame, because inside the copy assignment operator, another temporary copy is being created and destroyed. That's extra work, for nothing.
Well, no more. C++11 gives us rvalue references with which we can implement "move semantics", and in particular a "move assignment operator" [5] . Let's add another operator= to Intvec :
The && syntax is the new rvalue reference . It does exactly what it sounds it does - gives us a reference to an rvalue, which is going to be destroyed after the call. We can use this fact to just "steal" the internals of the rvalue - it won't need them anyway! This prints:
What happens here is that our new move assignment operator is invoked since an rvalue gets assigned to v2 . The constructor and destructor calls are still needed for the temporary object that's created by Intvec(33) , but another temporary inside the assignment operator is no longer needed. The operator simply switches the rvalue's internal buffer with its own, arranging it so the rvalue's destructor will release our object's own buffer, which is no longer used. Neat.
I'll just mention once again that this example is only the tip of the iceberg on move semantics and rvalue references. As you can probably guess, it's a complex subject with a lot of special cases and gotchas to consider. My point here was to demonstrate a very interesting application of the difference between lvalues and rvalues in C++. The compiler obviously knows when some entity is an rvalue, and can arrange to invoke the correct constructor at compile time.
One can write a lot of C++ code without being concerned with the issue of rvalues vs. lvalues, dismissing them as weird compiler jargon in certain error messages. However, as this article aimed to show, getting a better grasp of this topic can aid in a deeper understanding of certain C++ code constructs, and make parts of the C++ spec and discussions between language experts more intelligible.
Also, in the new C++ spec this topic becomes even more important, because C++11's introduction of rvalue references and move semantics. To really grok this new feature of the language, a solid understanding of what rvalues and lvalues are becomes crucial.
For comments, please send me an email .
- Basics of C / C language / C-Operators / Elements of C language
Assignment Operator in C Language | L- value Error in C programming
by Venkatesh
Introduction:
In our previous articles, we discussed the Arithmetic Operators in C Language . In today’s article, We will learn about the Assignment Operator in C Programming. We also discuss the L-Value error in programming.
Assignment Operator in C Langauge ( = ) :
The C programming language has assignment operators to create and assign values to the variables .
We represent the Assignment operator using the equal to( = ) symbol in C programming.
Syntax Of Assignment Operator:
The assignment operator is for used assigning values. In general assignment operator assigns the value of the right-hand ( R-Value) side operand to the Left-hand (L-Value) side Operand.
The assignment operator is a binary operator so it must need two operands.
The assignment operator has two values. The Left-side value is called as L-Value and The Right-side value is called as R-Value .
The Assignment Operation will copy the R-Value to L-Value .
The left-side value ( L-Value ) of the Assignment Operator must be a Variable .
The assignment operator has the Lowest Precedence or Priority compared to all other operators except Comma Operator.
For full Priority of Operators please visit – see full priority table/precedence table
Example Program to understand Assignment Operator:
In above Example x = 10 is assignment operation.
Here x is the left-side value or L-Value and The value 10 is the right-side value or R-Value, By using the assignment operator we assigned the value 10 to the variable x .
Program Output:
As you can see the value of x is 10 .
Example 2 : L – Value Error in C programming :
The Left-side value of the Assignment Operator must be Variable. So we basically trying to assign R-Value to L-Value. So L-Value must-have capacity to store the R-Value. But constants and numbers can’t store a value.
📢 The Left-side or L-Value of the Assignment Operator must be a Variable.
Program Output
Complex assignment operations in c programming:.
In the C programming language, We have few compound assignment operators to perform the assignments along with some other arithmetic operations.
For example,
x = 5 ; // simple assignment
x += 10 ; // compound operation
Simple Assginment Operation:
This is a simple assignment, Here we have created a variable x and assigned value 10 to x .
Compound Addition ( Add then Assigne += ):
This is a compound operation. Which is equal to
x = x + 20 ;
Here first x + 20 is calculated then x is updated with the resulting value of x + 20 operation.
Similarly, we can have other compound arithmetic operations, Please look at the following table for all compound Operations.
The Compound Assignment statements are elegant and try to use them in the programs.
Conclusion:
In this article, We discussed the Assignment Operators and Compound Assignment operators in the C language. We also looked at a few example code snippets and L-Value Error.
Related Tutorials:
- Start Here – Step by step tutorials to Learn C programming Online with Example Programs – SillyCodes
- Modulo operator in C explained with Examples.
- Arithmetic operators in C language.
- Compilation Stages in C language.
- Identifiers in C language and Rules for naming Identifiers.
- Structure of C Language.
Related Programs:
- Come Together – The Collection of all Pattern Programs in C – SillyCodes
- C codes Archives – SillyCodes
Share this:
Tags: C-Language C-Operators C-Tutorials
Hi Guys, I am Venkatesh. I am a programmer and an Open Source enthusiast. I write about programming and technology on this blog.
- Next story Write a C program to generate the first n terms of the sequence. | Fibonacci Sequence program in C
- Previous story Zombie process in linux | Zombie implementation in C | Linux process types
You may also like...
Pattern 20 : Hollow Mirrored right angle triangle pattern program in C using loops
Program to convert octal to decimal in C Language
Program to find the LCM of Two numbers in C Language
2 responses.
- Pingbacks 2
[…] Assignment Operators. […]
Leave a Reply Cancel reply
- History of C Language
- Low-Level Languages
- High-Level Language
- Machine Language/Code
- Features of C Language
- Hello World Program In C
- Compile and run C Program in Linux or Unix
- Compilation Stages in C
- Standard Input (stdin), Output (stdout), and Error (stderr) Streams
- Character Set of C
- Keywords of C
- Operators in C
- Constants In C
- Identifiers in C
- Variables in C
- Escape Sequences
- Datatypes in C
- Size and Ranges of Datatypes
- Comments in C
- Statements in C
- Format Specifier In C
- Arithmetic Operators in C
- Assignment operator in C
- Division operator behavior
- Modulus Operator in C
- Increment(Pre/Post) Operators
- Pre/Post Increment Examples
- Pre/Post Decrement
- Relational Operators
- Conditional Operator
- Logical Operators
- Comma Operator
- Sizeof Operator
- Precedence and Associativity
- Basic C Programs
- Bitwise Operators in C Summary ( |, &, ~, <<, >>, ^ Operators )
- Bitwise OR Operator ( | )
- Bitwise AND Operator ( & )
- Bitwise XOR Operator ( ^ )
- Bitwise Right Shift Operator ( >> )
- Bitwise Left Shift Operator ( << )
- One’s Complement Operator ( ~ )
- Decision making statements if and if else in C
- Nested if else and if else ladder in C
- Switch Statement in C Language with Example Programs
- If else statement practice programs
- Switch Statement Programs
- While loop in C Language with Example Programs
- For loop in C language with Example programs
- do while loop in C
- Infinite loop in C Programming
- break statement in C Language with Example programs
- Continue Statement in C Language with Examples
- goto Statement in C Language with Examples
- C Loops Practice Programs
- Functions in C Language with Example programs
- Type of Functions in C Programming Language
- Call by Value and Call by Address / Call by Reference in C
- Recursion in C Language with Example Programs
- Functions with Variable Arguments
- Function Practice Programs
- Recursion Practice Programs
- C Arrays – How to Create, Access, and Modify the arrays
- 2D arrays (Multi-dimensional arrays) in C
- Passing arrays to functions in C
- Array Practice Programs in C
- Matrix Programs in C
- Strings in C Language
- Diff ways Read and Print Strings in C
- String Programs in C
- Pointers in C – How to Create and use pointers
- Address of Operator in C (&)
- Dereference Operator in C (*)
- Pointer Arithmetic in C
- Pointer to Pointer or Double Pointer in C
- Pointers and Arrays in C
- Function Pointers in C
- Function Returning Pointer in C
- Void Pointer in C
- Wild Pointer in C
- Pointer to Array in C
- Array of Pointers in C
- Pointers Programs in C
- Dynamic Memory Allocation in C
- Structure of C Program
- Procedural Vs Structured Language
- Command Line Arguments
- Different Methods to SWAP