An understanding of the Left value "lvalue" and Right Value "rvalue"
Original address: http://bbs.chinaunix.net/viewthread.php? Tid = 749505 &
Read the post
"Hello" is of the const char *?
I found that many of my friends have incorrect understanding of "lvalue" and "rvalue". I will first talk about my understanding of this and hope it will be widely discussed by more friends. It also plays a role in attracting others.
Note: This is mainly for the Standard C language. (Thanks to whyglinux for correcting) |
First, describe what is "L-value" and "R-value".
Definition of "l-value:
Tcpl A.5: an object is a named region of storage, an L-value is an expression referring to an object. |
ISO/iec9899 wg14/n1124 P58: an L-value is an expression with an object type or an incomplete type other than void. |
Definition of "R-value:
C: A Reference Manual (th Edition) P203: an expression that is not an L-value is sometimes called an R-value because it can be only on the right-hand side of an assignment. |
We can see that tcpl and c99 wg14 (quasi-standard document) have some changes in the definition of "lvalue", which is broader.
The title of "l-value" comes from the value assignment operation,
ISO/iec9899 wg14/n1124 P58: the name "L-value" comes originally from the assignment e1 = e2, in which the left operand E1 is required to be a (modifiable) l-value. |
However, its meaning is not limited to this. "Lvalue" can also be divided into general "lvalue" and "modifiable lvalue ".
Note: Why not to mention: "lvalue" can also be divided into "unmodifiable lvalue" and "modifiable lvalue" The reason is that only the word "modifiable lvalue" appears in the standard but not the word "unmodifiable lvalue". You can understand this, but I personally do not advocate the introduction of specialized nouns in non-standard specifications, to avoid misunderstanding. Thanks to whyglinux. |
ISO/iec9899 wg14/n1124 P58: a modifiable lvalue is 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) wit a const-qualified type. |
The concept of "lvalue" can be used to analyze operators, that is, to see which operators can generate "lvalue" and which operators must have the left operand "lvalue ". For example:
For address (Void *) 0x800000ff * 0x800000ff is not "lvalue", because * 0x800000ff is of the void type, but cast operator can generate "lvalue ": * (Char *) 0x800000ff is "lvalue" and "modifiable lvalue ". * (Char *) 0x800000ff = 'a ';
Note: I am very sorry. This example is incorrect. Whyglinux brother pointed out: 0x800000ff is an integer and is not a pointer type. Therefore, * 0x800000ff is invalid. It cannot be left or right. You may want to explain * (void *) 0x800000ff, but it is obviously invalid. In addition, it is wrong to say that "cast operator can generate" lvalue. On the contrary, in standard C and C ++, the cast operator operation results in the right value. In fact, cast operator only generates The Extentions of the compiler (such as GCC) for the left value. In Standard C, it is clearly stated in the footer: "A cast does not yield an lvalue ." (Thank you, whyglinux brother) |
For the value assignment operation, the left operand must be "lvalue ". (You don't need to talk about this) |
In my opinion, "lvalue" and "rvalue" can be understood as follows:
"Lvalue" must correspond to a fixed memory space, which has been determined during compilation;
Note: Incorrect understanding here. This sentence may be valid for the definition of "lvalue" in tcpl, but there is a problem with the broader definition. According to the definition in ISO/iec9899 wg14/n1124, reference to non-void incomplete type is left. Therefore, it has nothing to do with whether the bucket is determined during compilation, whether it actually exists, and whether it can be accessed. Can this be understood as follows: "Lvalue" must correspond to a bucket and is a reference for non-void objects. (Thanks to whyglinux's elder brother) |
"Rvalue" can be understood as the value represented by a bucket or the value of an expression. It emphasizes the meaning of value.
We recommend that you understand the standard as follows:
ISO/iec9899 wg14/n1124 P58 footnote 53): it (lvalue) is perhaps better considered as representing an object "Locator value ". what is sometimes called "rvalue" is in this International Standard described as the "value of an expression ". |
Therefore, in my opinion, according to the definition of "rvalue", any amount with a definite value can be used as "rvalue", only according to the standard of C language, some quantities as "rvalue" will lead to "undefined behavior" or other unexpected problems.
"Lvalue" can be used as "rvalue", but "rvalue" cannot be used as "lvalue.
Note: Further explanation is required. "Lvalue" is defined in the C standard, while "rvalue" is defined based on "lvalue, it is equivalent to "error" defined as "incorrect" on the basis of "right ". Whyglinux brother pointed out that the concept of the left and right values is opposite. The left value can be used as the right value because of the lvalue-to-rvalue conversion specified in the C and C ++ standards. Although I did not find the original article (which of the following may tell me if I know it), I think it makes sense. Therefore, "lvalue" can be used as "rvalue" (but not all of them are suitable, because evaluate "lvalue" may obtain junk data or cause illegal operations ). On the other hand, an expression is "lvalue", which can be said to be "Born", but an expression is "rvalue", but there are two situations: one type is "Born" (for example, an integer constant of 100), and the other type is converted to "lvalue, this type of "rvalue" can be called "rvalue" (of course, in a specific context, because the definition of "rvalue" is closely related to the assignment operation of the Legal Method) it can also be called "lvalue", so this type of "rvalue" can be used as "lvalue. Therefore, "rvalue" may not be used as "lvalue". This is the main consideration. For example:
Code: int X; Int y = 10; X = y;/* here, the variable Y is defined as "lvalue", but it is converted to "rvalue". It can also be called a value assignment operation. "Rvalue "*/ Y = 100;/* Here, Y is used as "lvalue" based on its original type */ |
(Thanks to whyglinux for pointing out) |
For example:
1. "Hello world" is string literal (as whyglinux brother said in the post) and is of the array type. c Standard says string literal will be stored in the static storage area, and its elements have the char type (note: the standard ISO/iec9899 wg14/n1124 does not indicate that the elements have the const char type. In fact, the const keyword is not found in the old version C, it is used for reference from C ++ ). But "Hello World" does indicate the same meaning as const char. So let's talk about it. A little too far, so "Hello world" is not "lvalue "? The answer is: it is an unchangeable "lvalue ". You can analyze it as follows: "Hello World" has a certain data type, then, the memory address where it is located has been determined during compilation (a continuous space in a static storage area ).
2. Read the following code:
Code: char * P; * P = 'a '; Printf ("% C \ n", * P ); |
We can see that this is a piece of wrong code, which can be attributed to "incorrect use of assignment", because * P is not
"Lvalue", because P points to an object that cannot be determined during compilation, the memory space corresponding to * P is uncertain.
Note: This is totally incorrect. According to the definition of "lvalue" in ISO/iec9899 wg14/n1124, * P should be "lvalue ". (Thanks to Brother wolf0403 for being an axe) |
So * is P "rvalue? The answer is: it is "rvalue" by definition ". Because * P always has a value (only junk data or illegal access) during each running process ). So it should be said: * P is "rvalue", but it cannot be used as "rvalue" in practice.
Is P "lvalue? This is of course, it is "lvalue" and "modifiable lvalue", or how to initialize it?
Note: The "initialization" in the "otherwise how to initialize it" sentence should be "value assignment", which is not a written mistake. It is for the next Code and is a wrong idea. Haha. (Thanks to whyglinux's elder brother) |
The cause can also be analyzed as shown above.
Code: P = malloc (bufsiz * sizeof (* p )); |
3. "lvalue" can be used as "rvalue", but not all. Run the following code:
Note: there is an error. Any function call is not an "lvalue", and some standards also clearly indicate that the function name (function Designator) is not a left value, because function designator is a function type rather than an object type, so it is not "lvalue ". The example should be: it cannot be used as an example of "rvalue. (Thanks to whyglinux's elder brother) |
Code: void Foo (void) { /* Do something ...*/ } Int I; I = Foo ();/* function call is an expression, AND FOO () is "lvalue", but it cannot be used as "rvalue "*/ The Foo () function call here is not "lvalue ". |
4. Two examples of "native" being "rvalue"
Code: # define constant 10 Int num;Num = 3;/* integer, floating point number, character (not a string) constant "natural" is "rvalue "*/ Num = constant;/* The macro-defined constant is also "rvalue "*/ |
In fact, I think that a deep understanding of some original definitions in the C standard can not only gain a deeper understanding of the C language itself, but also directly go deep into the root cause when looking for problems, in this way, it is easier to find the cure. In this regard, I think domestic friends should cheer up compared with foreign counterparts. A very profound example is: once, I worked in comp. lang. c, when I saw a netizen posting a question, I gave this sentence to a piece of code:
Code: <snip> Int result; Int x = 3; Int y = 4; Result = max (x, y ); <Snip> |
The parameters of the function max in the function call statement...
Someone immediately pointed out that "Parameters" is incorrect. It should be "arguments", because "Parameters" is used to describe the form parameter, and "arguments" is used to describe the real parameter. This may be a linguistic difference, but one thing is the same, that is, "argument" and "parameter" have different meanings in the C standard.