can you explain why compile time error in the below code - c

why im getting errors in the code given below....
#include <stdio.h>
void foo(int*);
int main()
{
int i = 10;
foo((&i)++);(in this line error shows like this) //error: lvalue required as increment operand
}
void foo(int *p)
{
printf("%d\n", *p);
}

From Member access operators:
The address-of operator produces the non-lvalue address of its operand, suitable for initializing a pointer to the type of the operand.
And from Increment/decrement operators:
The operand expr of both prefix and postfix increment or decrement must be a modifiable lvalue of integer type (including _Bool and enums), real floating type, or a pointer type.
Simply put the & operator does not produce an appropriate object for the ++ operator.

Related

Sizeof operator with variable-length array type

According to cppreference:
If the type of expression is a variable-length array type, expression
is evaluated and the size of the array it evaluates to is calculated
at run time.
It means: if the type of expression is a VLA type, then expression is evaluated. For example:
#include <stdio.h>
int main() {
int i = 0;
int a[i];
printf("%zu\n",sizeof(a[i++]));
printf("%d\n",i); // Here, print 0 instead of 1
return 0;
}
So, according to the reference, here i becomes 1. But, with my GCC compiler, i prints as 0.
See Wandbox Demo.
First of all, please note that an array cannot have size zero, be it a VLA or not. So your code invokes undefined behavior.
C11 6.7.6.2/5
"If the size is an expression that is not an integer constant expression:" /--/ "...each time it is evaluated it shall have a value greater than zero."
As for the actual problem, a[i++] is of type int, not of VLA type.
In order to get the side-effect, you must involve the VLA array type itself, such as sizeof(a). Only then is the operand evaluated for side effects. One example to illustrate this:
#include <stdio.h>
int main() {
int i=1, j=1;
int a[i][j];
int b[1][1];
(void) sizeof(a[--i]);
(void) sizeof(b[--j]);
printf("%d %d", i, j);
return 0;
}
Here i ends up as 0 since the first sizeof is evaluated because of the VLA, but j remains 1 because --j was part of a sizeof for a regular array.
The expression in sizeof in your example is int, and not vla. If it were vla, all would work:
#include <stdio.h>
int main() {
int i = 5;
int a[i][i];
printf("%zu\n",sizeof(a[--i]));
printf("%d\n",i); // Here, print 4
return 0;
}
From C Standards#6.5.3.4p2 [emphasis mine]
The sizeof operator yields the size (in bytes) of its operand, which may be an expression or the parenthesized name of a type. The size is determined from the type of the operand. The result is an integer. If the type of the operand is a variable length array type, the operand is evaluated; otherwise, the operand is not evaluated and the result is an integer constant.
In the expression:
sizeof(a[i++])
the a[i++] is not VLA but a subscript operator expression resulting in an integer. So, the operand is not evaluated and for the same reason, compiler is giving warning on this statement:
warning: expression with side effects has no effect in an unevaluated context
To take the word of a clone of a normative references for it:
6.5.3.4 - The sizeof and _Alignof operators
The sizeof operator yields the size (in bytes) of its operand, which
may be an expression or the parenthesized name of a type. The size is
determined from the type of the operand. The result is an integer. If
the type of the operand is a variable length array type, the operand
is evaluated; otherwise, the operand is not evaluated and the result
is an integer constant.
It would be evaluated, if you fix your example to produce an expression with VLA type, one such way
#include <stdio.h>
int main() {
int i = 1;
int a[5][i];
printf("%zu\n",sizeof(a[i++]));
printf("%d\n",i);
return 0;
}
Prints 2 on the last line, because i is incremented.

why foo((&i)++) gives Lvalue required error. There is no array associated

I understand a few things about Lvalue but I don't understand how the below code gives an error:
#include<stdio.h>
void foo(int *);
int main()
{
int i=10;
foo((&i)++);
}
void foo(int *p)
{
printf("%d",*p);
}
6:13: error: lvalue required as increment operand
foo((&i)++);
^
x++ results following steps.
1) read the value of x in to register.
2) increment the value of x
3) write the incremented value back to x (which means you are changing the value of x by '1')
But what you are trying to do is (&i)++ which means the following.
1) read address of i into register
2) increment the address by 1
3) write the incremented value in to address again? How you can change the address?
If you want to send the integer which is stored in next address to foo(), you need to increment as below.
int *p = &i + 1;
foo(p);
But that may result in undefined behavior because you know only address of i where i value is stored. Once you increment the address, you will get next address and it may contain some junk value.
There is an attempt to apply the unary operator & to a temporary object that is evaluated as the expression (&i)++. You may not apply the operator to a temporary object.
C Standard (6.5.3.2 Address and indirection operators):
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.

Why It throws an error lvalue is required?

#include<stdio.h>
int main(){
int i=0,j=1;
printf("%d",++(i+j));
return 0;
}
In this code I have used the increment operator but i don't know why it throws an error.
It throws the error:
lvalue is required.
You are trying to increment an integer value that isn't assigned to a variable.
Taking your code, this is approximately what the computer will try to do:
printf("%d",++(i+j));
// expanded step 1
printf("%d",++(0+1));
// expanded step 2
printf("%d",++(1));
As you can see in the last version, you are trying to call ++1, which is invalid.
In order to increment a value using ++, the operand must have integral, floating, or pointer type and must be a modifiable l-value expression (an expression without the const attribute):
int x = i+j;
printf("%d",++x);
Alternatively, you can use the addition operator:
printf("%d",i+j+1);
You cant increment the result.
Instead:
printf("%d",i + j + 1);
In C you cannot apply an unary operator too a number. When the value between the parentesis is evaluated first... before use the unary operation. assing the result to a variable.
#include<stdio.h>
int main(){
int i=0,j=1, other_value=0;
other_value = i+j;
printf("%d",++(other_value));
return 0;
}
Your previus code will work will get the error
error: lvalue required as increment operand
An "lvalue" is a value that can be the target of an assignment. The "l" stands for "left", as in the left hand side of the equals sign. An rvalue is the right hand value and produces a value, and cannot be assigned to directly. If you are getting "lvalue required" you have an expression that produces an rvalue when an lvalue is required.
in your case when compiler manipulate the expression then it will result to invalid expression which is ++1
try below:
printf("%d",i+j+1);
The expression ++(i+j) is not assignable. Here, the expression (i+j) will get evaluated first. For the ++ operator, the operand must have integral, floating, or pointer type and must be a modifiable l-value expression. Since the result from i+j is a constant value, so you get the error lvalue required as increment operand. You can choose to modify this expression as i+j+1.

lvalue required as unary ‘&’ operand -- passing function result as pointer

I have some problem with my code.
There are the following functions:
static Poly PolyFromCoeff(int coeff);
static Mono MonoFromPoly(const Poly *p, int exp);
And in another function I have this line:
Mono m = MonoFromPoly(&PolyFromCoeff(10),4);
But I receive this error message:
lvalue required as unary ‘&’ operand
If I save the first result to a variable, there is no error:
Poly p = PolyFromCoeff(10);
Mono m = MonoFromPoly(&p,4);
Why is the first solution wrong?
As it says, operator & requires a lvalue as its argument, i.e. it cannot be applied to temporary values. Addresses are not associated with values, with objects only.
In the second form you instantiate an object that holds this value and you can easily take the address of that object.
The C language expressly prohibits you from taking the address of a rvalue (which is what a function returns). This clause from the C11 standard (committee draft) sums it up:
6.5.3.2 Address and indirection operators
Constraints
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.
If you are confused about lvalue and rvalue, think of it like this:
lvalue is something that has an identifier and storage
rvalue is a temporary result or literal value
If you have a C++ background, you might have been confused because the behavior of references is different. In C++, it's okay to have this:
static Poly PolyFromCoeff(int coeff);
static Mono MonoFromPoly(const Poly &p, int exp);
Mono m = MonoFromPoly( PolyFromCoeff(10), 4 );

Address of dereferenced pointer construct

In unqlite c library I found following code:
pObj = jx9VmReserveMemObj(&(*pVm),&nIdx);
where pVm is:
typedef struct jx9_vm jx9_vm;
jx9_vm *pVm
and function called is declared as:
jx9_value * jx9VmReserveMemObj(jx9_vm *, sxu32 *);
What for construct &(*pVm) is used in call instead of just pVm? Is &(*pVm) equivalent to pVm?
Quoting C11, chapter §6.5.3.2, Address and indirection operators
[...] 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, yes, they are equivalent.
This construct can be used, however, to check the type of the argument against a pointer type. From the property of unary * operator,
The operand of the unary * operator shall have pointer type.
So, the construct &(*pVm)
will be fine, if pvm is a pointer or array name.
will generate compiler error, if pvm is a non-pointer type variable.
See the other answer by Alter Mann for code-wise example.
One more difference (in general) is, pVm can be assigned (can be used as LHS of the assignment operator), but &(*pVm) cannot.
Is &(*pVm) equivalent to pVm?
Yes. *1
Same for *(&pVm).
(*1)
As the *-operator (de-referencing) only is applicable to pointers, the former construct only works on a pointer (or an array, which would decay to a pointer to its 1st element). The latter can be applied to any type of variable.:
Yes, they are the same, but notice that it fails when the object is not an array or a pointer:
#include <stdio.h>
struct t {
int value;
};
typedef struct t t;
int func(t *ptr)
{
return ptr->value;
}
int main(void)
{
t o = {.value = 0};
t v[2] = {{.value = 1}, {.value = 2}};
printf("%d\n", func(&(*o))); /* error: invalid type argument of unary ‘*’ */
printf("%d\n", func(&(*v))); /* WORKS */
return 0;
}

Resources