The operators in the productions below expect the first operand to identify an object, and modify its value.
- unary-expression
-
++ unary-expressionSide-effects -
-- unary-expressionSide-effects - postfix-expression
-
postfix-expression ++Side-effects -
postfix-expression --Side-effects - assignment-expression
unary-expression assignment-operator assignment-expression- assignment-operator
=*=/=%=+=-=<<=>>=&=^=|=
Such a modification is called a side-effect, and it is the only way to modify the value of an object. An expression that identifies an object is an l-value, pronounced ‘el value’. If the object can be modified using that expression, the expression is a modifiable l-value. Operators with side-effects require the first operand to be a modifiable l-value.
Expressions are often useful for their side-effects alone, with the result being discarded. This happens most often in expression statements:
(Other places include the initializer and increment of a
for loop, and
the left operand of the comma operator (see expression).)
Given the following declarations:
int x; int *xp = &x; int arr[10] = { 0 }; // All zero
…here are a dozen or so expression statements with their side-effects explained:
// The l-value is a simple variable name. x = 10; // Setxto10. x++; // Setxto11. x--; // Setxto10. ++x; // Setxto11. --x; // Setxto10. // The l-value identifies an object by dereferencing its address. *xp = 6; // Setxto6. (*xp)++; // Setxto7. --*xp; // Setxto6. // The l-value identifies an object in an array. arr[3] = 10; // Setarr[3]to10. ++arr[4]; // Setarr[4]to1. arr[5]--; // Setarr[5]to-1. arr[x - 2] -= 3; // Setarr[4]to-2.
The operator ++ increments the
object by one, while -- decrements by
one. The simple assignment operator =
assigns the value of its right operand to the object
identified by the left operand. The operator -= decrements the object on the left by the value
on the right. Other operators behave similarly, i.e., x
op= y is equivalent to
x = (x) op
(y).
As expressions, all these operators yield a value,
although it can be, and often is, ignored. The assignment
operators yield the value that is assigned, permitting
expressions such as x = y = z, which
assigns the value of z to both
x and y. The
operators ++ and -- yield a value depending on whether the operand
is to the left or right of the operator. ++x yields the new value of x; x++ yields the previous
value of x.
Unmodifiable l-values are array names, and l-values of
types qualified with
const:
char arr[10]; const char *p = arr; char *q; arr = q; // Error; arrays cannot be moved. *(arr + 4) = 'c'; // Okay;arr + 4has typechar *. arr[4] = 'c'; // Okay; same as above. *(p + 4) = 'c'; // Error;p + 4has typeconst char *. p[4] = 'c'; // Error; same as above.
Although *(p + 4) identifies an
object, and is therefore an l-value, p +
4 has type const char *, so
*(p + 4) must have type const char, and that
makes it unmodifiable.
Some expressions are used to invoke functions, and follow this grammar:
Depending on what it has access to, the invoked function may produce side-effects of its own.