First of all, I think it's a rvalue, but the following fact changed my mind.
I tried an expression as &(*&a) and it works fine, but the operator & can just work with a lvalue, so (*&a) is a lvalue, why?
Per C 2018 6.5.3.2 4 (discussing the unary * operator), the result of unary * is an lvalue:
… If the operand points to a function, the result is a function designator; if it points to an object, the result is an lvalue designating the object.…
This tells us that *&a is an lvalue. However, the expression asked about in the question is (*&a), so we must consider the effect of the parentheses.
6.3.2.1 2 (discussing automatic conversions) seems to tell us that (*&a) is converted to the value in *&a and is not an lvalue:
Except when it is the operand of the sizeof operator, the unary & operator, the ++ operator, the -- operator, or the left operand of the . operator or an assignment operator, an lvalue that does not have array type is converted to the value stored in the designated object (and is no longer an lvalue); this is called lvalue conversion.
However, 6.5.1 5 (discussing parenthesized expressions) contradicts this:
A parenthesized expression is a primary expression. Its type and value are identical to those of the unparenthesized expression. It is an lvalue, a function designator, or a void expression if the unparenthesized expression is, respectively, an lvalue, a function designator, or a void expression.
This is a defect in the C standard; 6.5.1 5 and 6.3.2.1 2 contradict each other. It is left to us to understand that 6.5.1 5, which is specifically about parenthesized expressions, takes precedence over the more general 6.3.2.1 2, and this is how all C implementations behave.
Thus (*&a) is an lvalue.
This expression &(&a) is invalid and will not work.
According to the C Stnadard
1 The operand of the unary & operator shall be either a function
designator, the result of a [] or unary * operator, or an lvalue
that designates an object that is not a bit-field and is not declared
with the register storage-class specifier.
and
3 The unary & operator yields the address of its operand. If the
operand has type ‘‘type’’, the result has type ‘‘pointer to type’’. If
the operand is the result of a unary * operator, neither that operator
nor the & operator is evaluated and the result is as if both were
omitted, except that the constraints on the operators still apply
and the result is not an lvalue.
So the result of the expression &a is not an lvalue. So you may not apply the operator & to the expression like &&a.
Here is a demonstrative program.
#include <stdio.h>
int main(void)
{
int x = 10;
&( &x );
return 0;
}
The compiler gcc 8.3 issues an error
prog.c: In function ‘main’:
prog.c:7:2: error: lvalue required as unary ‘&’ operand
&( &x );
^
This expression *&a is valid and the result is an lvalue.
4 The unary * operator denotes indirection. If the operand points to a
function, the result is a function designator; if it points to an
object, the result is an lvalue designating the object. If the
operand has type ‘‘pointer to type’’, the result has type ‘‘type’’. If
an invalid value has been assigned to the pointer, the behavior of the
unary * operator is undefined.
Bear in mind that parentheses do not influence on whether the enclosed expression is an lvalue or not.
Related
C2x, 6.5.3.2 Address and indirection operators, Constraints, 2:
The operand of the unary * operator shall have pointer type.
Why there is no constraint "the operand shall not be a pointer to void"?
Though it can be deduced from:
C2x, 6.5.3.2 Address and indirection operators, Semantics, 4:
The unary * operator denotes indirection. If the operand points to a function, the result is a function designator; if it points to an object, the result is an lvalue designating the object.
C2x, 6.3.2.1 Lvalues, arrays, and function designators, 1:
An lvalue is an expression (with an object type other than void) that potentially designates an object; ...
One possible (though somewhat contrived, I'll admit) case where adding your 'suggested' constraint would break code is where the & and * operators are concatenated. In such cases, an expression such as a = &*p, where p is a void* type, is allowed.
From this Draft Standard, immediately following the section in your first citation (bold emphasis mine):
Semantics
3 The unary & operator yields the address of its
operand. If the operand has type ‘‘type’’, the result has type
‘‘pointer to type’’. If the operand is the result of a unary *
operator, neither that operator nor the & operator is evaluated
and the result is as if both were omitted, except that the
constraints on the operators still apply and the result is not an
lvalue. …
I can't, currently, think of a use-case for that &* combination (on a void* or any other pointer type) – but it may occur in code that is "auto-generated" and/or uses conditional macro expansion(s).
I was told that the array name is an non-modifiable l-value in C, but it is still confusing.
Someone said that the array name can not be placed on the left side of the formula because it is converted to a pointer that is not l-value.
My question is Here:
is an array name l-value?
Is there any difference between what means l-value in c and c++?
is an array name l-value?
Yes, in both C and C++.
Is there any difference between what means l-value in c and c++?
Yes, but not of great significance. Here is the definition from C11, paragraph 6.3.2.1/1:
An lvalue is an expression (with an object type other than void) that potentially designates an object
C also includes a footnote (#64) expanding on that, which includes:
The name ''lvalue'' comes originally from the assignment expression E1 = E2, in which the left operand E1 is required to be a (modifiable) lvalue. It is perhaps better considered as representing an object
''locator value''. [...] An
obvious example of an lvalue is an identifier of an object.
Here is the definition from C++14, paragraph 3.10/1:
An lvalue (so called, historically, because lvalues could appear on
the left-hand side of an assignment expression) designates a function
or an object.
If you read carefully, you will notice that in C, an lvalue only potentially designates an object, whereas in C++, no room is left for unfulfilled potential -- an lvalue does designate an object or function. You'll also then notice that C++ includes function designators among its lvalues, whereas C does not. In practice, these distinctions are more technical than deeply meaningful. And neither of them affects the answer to your question (1).
You'll also note that neither definition is written in terms of how or where an lvalue can be used. That follows from the definition and other specifications; it is not a defining characteristic.
In both C and C++, an array's identifier designates an object -- the array -- and it is therefore an lvalue. Whether such an lvalue may in fact appear as the left operand in an assignment expression is an entirely separate question.
In the context of C:
6.3.2.1 Lvalues, arrays, and function designators
1 An lvalue is an expression (with an object type other than void) that potentially
designates an object;64) if an lvalue does not designate an object when it is evaluated, the
behavior is undefined. When an object is said to have a particular type, the type is
specified by the lvalue used to designate the object. 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) with a const-qualified type.
2 Except when it is the operand of the sizeof operator, the _Alignof operator, the
unary & operator, the ++ operator, the -- operator, or the left operand of the . operator
or an assignment operator, an lvalue that does not have array type is converted to the
value stored in the designated object (and is no longer an lvalue); this is called lvalue
conversion. If the lvalue has qualified type, the value has the unqualified version of the
type of the lvalue; additionally, if the lvalue has atomic type, the value has the non-atomic
version of the type of the lvalue; otherwise, the value has the type of the lvalue. If the
lvalue has an incomplete type and does not have array type, the behavior is undefined. If
the lvalue designates an object of automatic storage duration that could have been
declared with the register storage class (never had its address taken), and that object
is uninitialized (not declared with an initializer and no assignment to it has been
performed prior to use), the behavior is undefined.
3 Except when it is the operand of the sizeof operator, the _Alignof operator, or the
unary & operator, or is a string literal used to initialize an array, an expression that has
type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points
to the initial element of the array object and is not an lvalue. If the array object has
register storage class, the behavior is undefined.
64) The name ‘‘lvalue’’ comes originally from the assignment expression E1 = E2, in which the left
operand E1 is required to be a (modifiable) lvalue. It 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’’.
An obvious example of an lvalue is an identifier of an object. As a further example, if E is a unary
expression that is a pointer to an object, *E is an lvalue that designates the object to which E points.
C 2011 Online Draft
Summarizing:
An array expression (that is, any expression of array type) is indeed an lvalue; however, unless it is the operand of the sizeof, _Alignof, or unary & operators, that expression gets converted ("decays") to an expression of pointer type whose value is the address of the first element of the array, and that converted pointer expression is not an lvalue, and thus cannot be the target of an assignment.
That is, if you declare a as
T a[N]; // for any type `T`
then the expression a has type "N-element array of T". If a is not the operand of the sizeof, unary &, or _Alignof operators, it will be converted to an expression of type "pointer to T", and its value will be the same as &a[0], and that value cannot be the target of an assignment (it's logically the same as writing 2 = 3 - you're trying to assign a value to a value, not an object, which doesn't work).
C 2011 (draft N1570) 6.3.2.1 3 says:
Except when it is the operand of the sizeof operator, the _Alignof operator, or the unary & operator, or is a string literal used to initialize an array, an expression that has type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points to the initial element of the array object and is not an lvalue. If the array object has register storage class, the behavior is undefined.
C 2018 6.3.2.1 3 says:
Except when it is the operand of the sizeof operator, or the unary & operator, or is a string literal used to initialize an array, an expression that has type "array of type" is converted to an expression with type "pointer to type" that points to the initial element of the array object and is not an lvalue. If the array object has register storage class, the behavior is undefined.
Why is _Alignof missing from the latter?
C 2018 Foreward 7 says:
There are no major changes in this edition, only technical corrections and clarifications.
This implies there was something incorrect about exempting _Alignof from the array conversion rule, causing it to be removed. However, it should be possible to apply _Alignof to arrays, as C 2018 6.5.3.4 3 says:
The _Alignof operator yields the alignment requirement of its operand type. The operand is not evaluated and the result is an integer constant. When applied to an array type, the result is the alignment requirement of the element type.
In both the C11 and C18 Standards, the _Alignof operator may have a type name as an operand, but not an expression. From §6.5.3 of the C11 Draft Standard:
Syntax
unary-expression:
postfix-expression
++ unary-expression
-- unary-expression
unary-operator cast-expression
sizeof unary-expression
sizeof ( type-name )
_Alignof ( type-name )
unary-operator: one of
& * + - ~ !
The sizeof operator may have either an expression or a parenthesized type name as an operand, but since it is a constraint violation to use anything other than a parenthesized type name as the argument to _Alignof, there is simply no need for the special exception for array conversions here.
It turns out that the change was made between the release of the N1570 Draft Standard and the final release of the C11 Standard (ISO/IEC 9899:2011). There is some discussion in this SO answer, which references discussion in this Google Groups thread in which Larry Jones of the ISO C Committee suggests that:
The biggest change was removing _Alignof from a
bunch of places it shouldn't have been added (based on the erroneous
notion that it takes either a type or an expression like sizeof does
when it really only takes a type): 6.3.2.1p2, p3, p4, fn. 65; and 6.7.1
fn. 121.
The expressions x++; and x*2; are reported as illegal. Compiler generates error. However, in case of x+1; there's no error reported.
Can anyone help me understand why the particular expressions are illegal? Or, in other way, why the addition is legal?
Code:
#include <stdio.h>
int main(void)
{
int x[]={1,2,3,4,5};
x++;
x+1;
x*2;
}
Among these three statements
x++;
x+1;
x*2;
there is only two statements are illegal. This statement
x+1;
is correct. In this case in the expression the array designator is converted to pointer to its first element.
Multiplicative operators are not defined for pointers. So this statement
x*2;
is illegal.
Arrays are non-modifiable lvalues. You may not change an array designator. So this statement
x++;
is illegal.
Actually, you need to understand how and when the operators are allowed. Let's see one by one.
Quoting from C11,
++, Postfix increment, chapter §6.5.2.3
The operand of the postfix increment or decrement operator shall have atomic, qualified,
or unqualified real or pointer type, and shall be a modifiable lvalue.
+, Additive operator, chapter §6.5.6
For addition, either both operands shall have arithmetic type, or one operand shall be a
pointer to a complete object type and the other shall have integer type. (Incrementing is
equivalent to adding 1.)
*, Multiplicative operator, chapter §6.5.5
Each of the operands shall have arithmetic type. [...]
Now, in your usage
x++; --> x is not a modifiable lvalue, it is of "array type". This causes error.
x+1; --> Satisfies the requirement see notes for array decay, hence valid.
x*2; --> x is not arithmetic type (its'a pointer type), hence invalid.
Additional notes: (all emphasis mine)
"Modifiable lvalue:"
Quoting chapter §6.3.2.1,
An lvalue is an expression (with an object type other than void) that potentially
designates an object; [...] 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) with a const-qualified
type.
"Arithmetic Type:"
Quoting §6.2.5,
Integer and floating types are collectively called arithmetic types. [...]
"Array decay:"
Quoting §6.3.2.1,
Except when it is the operand of the sizeof operator, the _Alignof operator, or the
unary & operator, or is a string literal used to initialize an array, an expression that has
type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points
to the initial element of the array object and is not an lvalue. [...]
Here, x is an array and you cannot modify the address of an array. It is illegal in C.
GCC compiler gives an error :
In function 'main':
5:5: error: lvalue required as increment operand
x++;
^
7:5: error: invalid operands to binary * (have 'int *' and 'int')
x*2;
Having trouble understanding, How following statement would be evaluated :
++*++ptr and *ptr++++
As per my understanding first would give me lValue required because after * is applied it would give value which cannot be used for ++ operator. But, the result is opposite. Please explain.
Second statement gives me error : batch3.c:6:21: error: lvalue required as increment operand
printf("%d", *ptr++++);
First, some standardese:
6.5.2.4 Postfix increment and decrement operators
Constraints
1 The operand of the postfix increment or decrement operator shall have atomic, qualified,
or unqualified real or pointer type, and shall be a modifiable lvalue.
Semantics
2 The result of the postfix ++ operator is the value of the operand. As a side effect, the
value of the operand object is incremented (that is, the value 1 of the appropriate type is
added to it). See the discussions of additive operators and compound assignment for
information on constraints, types, and conversions and the effects of operations on
pointers. The value computation of the result is sequenced before the side effect of
updating the stored value of the operand. With respect to an indeterminately-sequenced
function call, the operation of postfix ++ is a single evaluation. Postfix ++ on an object
with atomic type is a read-modify-write operation with memory_order_seq_cst
memory order semantics.98)
...
6.5.16 Assignment operators
...
3 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,111) but is not
an lvalue. The type of an assignment expression is the type the left operand would have
after lvalue conversion. The side effect of updating the stored value of the left operand is
sequenced after the value computations of the left and right operands. The evaluations of
the operands are unsequenced.
Emphasis mine.
The upshot of that wall of text is that the results of the expressions ptr++ and ++ptr are not lvalues. However, both expressions result in pointer values, so they may be the operands of the unary * operator, and the results of *ptr++ and *++ptr may be lvalues.
This is why ++*++ptr works; you're incrementing the result of *++ptr, which may be an lvalue. However, *ptr++++ is parsed as *(((ptr)++)++) (postfix ++ has higher precedence than unary *); the result of ptr++ is the operand to the second ++, but since the result of ptr++ is not an lvalue, the compiler complains. If you had written it as (*ptr++)++, then the expression would be valid.
In short:
++*++ptr - valid, equivalent to ++(*ptr++)
*++++ptr - invalid, equivalent to *(++(++ptr)), result of ++ptr is not an lvalue
++++*ptr - invalid, equivalent to ++(++(*ptr)), result of ++*ptr is not an lvalue
*ptr++++ - invalid, equivalent to *((ptr++)++), result pf ptr++ is not an lvalue
(*ptr)++++ - invalid, equivalent to ((*ptr)++)++, result of (*ptr)++ is not an lvalue
(*ptr++)++ - valid
++ operator has higher precedence over *
So the pointer will be incremented first and then dereferenced.
*p++
First
p++
Then *p++
For ++ there has to be a value which needs to be incremented. But the below expression doesn't provide the lvalue for the ++ . p++ is not a modifiable lvalue.
*ptr++++;
Considering that these two expressions are separate (note that and is defined <iso646.h>) here what happens:
First one ++*++ptr is equivalent to ++(*(++ptr)), as both prefix ++ and unary * have the same precedence and assiociativity is from right to left for both of them. See following example as an illustration:
#include <stdio.h>
int main(void)
{
int a[] = {1, 2};
int *ptr = a;
++(*(++ptr));
printf("%d\n", a[0]);
printf("%d\n", a[1]);
return 0;
}
Result:
1
3
The latter expression is not compilable, as ptr++ subexpression is not a modifiable lvalue. Note that postix ++ has higher precedence, that * (indirection operator) and its associativity is from left to right.