You write expressions to determine values, to alter values stored
in objects, and to call functions that perform input and output. In
fact, you express all computations in the program by writing expressions.
The translator must evaluate some of the expressions you write
to determine properties of the program. The translator or the target
environment must evaluate other expressions prior to program startup
to determine the initial values stored in objects with static duration.
The program evaluates the remaining expressions when it executes.

This document describes briefly just those aspect
of expressions most relevant to the use of the Standard C library:

An
address constant expression
specifies a value that has a pointer type
and that the translator or target environment can determine
prior to program startup.

A constant expression
specifies a value that the translator or target environment can determine
prior to program startup.

An
integer constant expression
specifies a value that has an integer type
and that the translator can determine at the point in
the program where you write the expression.
(You cannot write a function call, assigning operator,
or comma operator except as part of the operand of a
sizeof operator.)
In addition, you must write only subexpressions
that have integer type. You can, however,
write a floating-point constant expression as the operand of an integer
type cast operator.

A
floating-point constant expression
specifies a value that has a floating-point type
and that the translator can determine at the point in
the program where you write the expression.
(You cannot write a function call, assigning operator,
or comma operator except as part of the operand of a
sizeof operator.)
In addition, you must write only subexpressions
that have integer or floating-point type.

An lvalue expression
An lvalue expression designates an object that has
an object type other than an array type. Hence, you can access the
value stored in the object.
A modifiable lvalue expression designates an object that has
an object type other than an array type or a const type. Hence,
you can alter the value stored in the object.
You can also designate objects with an lvalue expression
that has an array type or an incomplete type,
but you can only take the address of such an expression.

Promoting occurs for an
expression whose integer type is not one of the ``computational'' types.
Except when it is the operand of the
sizeof operator,
an integer
rvalue expression
has one of four types:
int, unsigned int, long, or unsigned long.
When you write an expression in an rvalue context and the expression
has an integer type that is not one of these types, the translator
promotes its type to one of these.
If all of the values representable in the
original type are also representable as type int, then the
promoted type is int. Otherwise, the promoted type is
unsigned int. Thus, for signed char, short,
and any signed bitfield type, the promoted type is int.
For each of the remaining integer types (char, unsigned char,
unsigned short, any plain bitfield type,
or any unsigned bitfield type), the effect of these rules
is to favor promoting to int wherever possible, but to promote
to unsigned int if necessary to preserve the original value
in all possible cases.

An rvalue expression
is an expression whose value can be determined only when the program executes.
The term also applies to expressions which need not
be determined until program execution.

You use the sizeof operator,
as in the expression sizeof X
to determine the size in bytes of an object whose type
is the type of X. The translator uses the expression
you write for X only to determine a type;
it is not evaluated.