United States |
Previous | Contents | Index |
When two or more expressions are separated by the comma operator, they evaluate from left to right. The result has the type and value of the rightmost expression (although side effects of the other expressions, if any, do take place). The result is not an lvalue. In the following example, the value 1 is assigned to R , and the value 2 is assigned to T :
R = T = 1, T += 2, T -= 1; |
Side effects for each expression are completed before the next expression is evaluated.
A comma expression must be enclosed with parentheses if it appears where commas have some other meaning, as in argument and initializing lists. Consider the following expression:
f(a, (t=3,t+2), c) |
This example calls the function
f
with the arguments
a
,
5
, and
c
. In addition, variable
t
is assigned the value
3
.
6.9 Constant Expressions
A constant expression is an expression that contains only constants. A constant expression can be evaluated during compilation rather than at run time, and can be used in any place that a constant can occur. In the following example, limit+1 is a constant expression, and is evaluated at compile time:
#define limit 500 char x[limit+1] |
A constant expression cannot contain assignment, increment, decrement, function-call, or comma operators, except when they are within the operand of a sizeof operator. Each constant expression must evaluate to a constant that is in the range of representable values for its type.
There are several contexts in which C requires an expression that must evaluate to a constant:
An integral constant expression has an integral type and contains only operands that are integer constants, enumeration constants, character constants, sizeof expressions whose operand does not have variable-length array type or a parenthesized name of such a type, or floating constants that are the immediate operands of casts. Cast operands in an integral constant expression only convert arithmetic types to integral types, except as part of an operand to the sizeof operator.
C allows more latitude for constant expressions in initializers. Such a constant expression can evaluate to one of the following:
An arithmetic constant expression has an arithmetic type and contains
only operands that are integer constants, floating constants,
enumeration constants, character constants, or
sizeof
expressions whose operand does not have variable-length array type or a
parenthesized name of such a type. Cast operators in an arithmetic
constant expression only convert arithmetic types to arithmetic types,
except as part of an operand to the
sizeof
operator.
6.9.3 Address Constants
An address constant is a pointer to an lvalue designating an object of
static storage duration (see Section 2.10), or to a function
designator. Address constants must be created explicitly by using the
unary
&
operator, or implicitly by using an expression of array or function
type. The array subscript
[]
and member access operators
.
and -->, the address & and indirection * unary operators, and
pointer casts can be used to create an address constant, but the value
of an object cannot be accessed by use of these operators.
6.10 Compound Literal Expressions
A compound literal, also called a constructor expression, is a form of expression that constructs the value of an object, including objects of array, struct, or union type.
In the C89 Standard, passing a struct value to a function typically involves declaring a named object of the type, initializing its members, and passing that object to the function. With the C9x Standard, this can now be done with a single compound literal expression. (Note that compound literal expressions are not supported in the common C, VAX C, and Strict ANSI89 modes of the Compaq C compiler.)
A compound literal is an unnamed object specified by a syntax consisting of a parenthesized type name (the same syntax as a cast operator1) followed by a brace-enclosed list of initializers. The value of this unnamed object is given by the initializer list. The initializer list can use the designator syntax.
For example, to construct an array of 1000 int s that are all zero except for array element 9, which is to have a value of 5, you can write the following:
(int [1000]){[9] = 5}. |
A compound literal object is an lvalue. The object it designates has static storage duration if it occurs outside all function definitions. Otherwise, it has automatic storage duration associated with the nearest enclosing block.
|
The following examples illustrate the use of compound literals.
#1 |
---|
int *p = (int []){2, 4}; |
This example initializes p to point to the first element of an array of two int s, the first having the value 2 and the second having the value 4. The expressions in this compound literal are required to be constant. The unnamed object has static storage duration.
#2 |
---|
void f(void) { int *p; /*...*/ p = (int [2]){*p}; /*...*/ } |
In this example, p is assigned the address of the first element of an array of two int s, the first having the value previously pointed to by p and the second having the value zero. The expressions in this compound literal need not be constant. The unnamed object has automatic storage duration.
#3 |
---|
drawline((struct point){.x=1, .y=1}, (struct point){.x=3, .y=4}); Or, if drawline instead expected pointers to struct point: drawline(&(struct point){.x=1, .y=1}, &(struct point){.x=3, .y=4}); |
Initializers with designations can be combined with compound literals. Structure objects created using compound literals can be passed to functions without depending on member order.
#4 |
---|
(const float []){1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6} |
A read-only compound literal can be specified through constructions like the one in this example.
#5 |
---|
"/tmp/testfile" (char []){"/tmp/testfile"} (const char []){"/tmp/testfile"} |
The three expressions in this example have different meanings:
The first always has static storage duration and has type "array of char", but need not be modifiable.
The last two have automatic storage duration when they occur within the body of a function, and the first of these two is modifiable.
#6 |
---|
(const char []){"abc"} == "abc" |
Like string literals, const -qualified compound literals can be placed into read-only memory and can even be shared. This example might yield 1 if the literal's storage is shared.
#7 |
---|
struct int_list { int car; struct int_list *cdr; }; struct int_list endless_zeros = {0, &endless_zeros}; eval(endless_zeros); |
Because compound literals are unnamed, a single compound literal cannot specify a circularly linked object. In this example, there is no way to write a self-referential compound literal that could be used as the function argument in place of the named object endless_zeros .
#8 |
---|
struct s { int i; }; int f (void) { struct s *p = 0, *q; int j = 0; while (j < 2) q = p, p = &((struct s){ j++ }); return p == q && q->i == 1; } |
As shown in this example, each compound literal creates only a single * object in a given scope.
The function f() always returns the value 1.
1 However, this differs from a cast expression in that a cast specifies a conversion to scalar types or void only, and the result of a cast expression is not an lvalue. |
C performs data-type conversions in the following four situations:
The following sections describe how operands and function arguments are
converted.
6.11.1 Usual Arithmetic Conversions
The following rules---referred to as the usual arithmetic conversions---govern the conversion of all operands in arithmetic expressions. The effect is to bring operands to a common type, which is also the type of the result. The rules govern in the following order:
The following sections elaborate on the usual arithmetic conversion
rules.
6.11.1.1 Characters and Integers
A
char
,
short int
, or
int
bit field, either signed or unsigned, or an object that has enumeration
type, can be used in an expression wherever an
int
or
unsigned int
is permitted. If an
int
can represent all values of the original type, the value is converted
to an
int
. Otherwise, it is converted to an
unsigned int
. These conversion rules are called the integral promotions.
This implementation of integral promotion is called value
preserving, as opposed to unsigned preserving in which
unsigned char
and
unsigned short
widen to
unsigned int
. Compaq C uses value-preserving promotions, as required by the
ANSI C standard, unless the common C mode is specified.
To help locate arithmetic conversions that depend on unsigned
preserving rules, Compaq C, with the check option enabled, flags
any integral promotions of
unsigned char
and
unsigned short
to
int
that could be affected by the value-preserving approach for integral
promotions.
All other arithmetic types are unchanged by the integral promotions.
In Compaq C, variables of type
char
are bytes treated as signed integers. When a longer integer is
converted to a shorter integer or to
char
, it is truncated on the left; excess bits are discarded. For example:
This code assigns hex 41 (
'A'
) to
c
. The compiler converts shorter signed integers to longer ones by sign
extension.
int i;
char c;
i = 0xFFFFFF41;
c = i;
6.11.1.2 Signed and Unsigned Integers
Conversions also take place between the various kinds of integers.
When a value with an integral type is converted to another integral type (such as int converted to long int ) and the value can be represented by the new type, the value is unchanged.
When a signed integer is converted to an unsigned integer of equal or greater size, and the signed integer value is nonnegative, its value is unchanged. If the signed integer value is negative, then:
When an integer value is demoted to an unsigned integer of smaller size, the result is the nonnegative remainder of the value divided by the number one greater than the largest representable unsigned value for the new integral type.
When an integer value is demoted to a signed integer of smaller size, or an unsigned integer is converted to its corresponding signed integer, the value is unchanged if it is small enough to be represented by the new type. Otherwise, the result is truncated; excess high-order bits are discarded and precision is lost.
Conversion between integral types of the same size, whether signed or
unsigned, results in no machine-level representation change.
6.11.1.3 Floating and Integral
When a floating-type operand is converted to an integer, the fractional
part is discarded.
When a floating-type value is to be converted at compile time to an
integer or another floating type, and the result cannot be represented,
the compiler reports a warning in the following instances:
When a value of integral type is converted to floating type, and the
value is in the range of values that can be represented, but not
exactly, the result of the conversion is either the next higher or next
lower value, whichever is the natural result of the conversion on the
hardware. See your Compaq C documentation for the conversion
result on your platform.
6.11.1.4 Floating Types
If an operand of type float appears in an expression, it is treated as a single-precision object unless the expression also involves an object of type double or long double , in which case the usual arithmetic conversion applies.
When a float is promoted to double or long double , or a double is promoted to long double , its value is unchanged.
The behavior is undefined when a
double
is demoted to
float
, or a
long double
to
double
or
float
, if the value being converted is outside the range of values that can
be represented.
If the value being converted is inside the range of values that can be
represented, but not exactly, the result is rounded to either the next
higher or next lower representable
float
value.
6.11.2 Pointer Conversions
Although two types (for example, int and long ) can have the same representation, they are still different types. This means that a pointer to int cannot be assigned to a pointer to long without using a cast. Nor can a pointer to a function of one type be assigned to a pointer to a function of a different type without using a cast. In addition, pointers to functions that have different parameter-type information, including the old-style absence of parameter-type information, are different types. In these instances, if a cast is not used, the compiler issues an error. Because there are alignment restrictions on some target processors, access through an unaligned pointer can result in a much slower access time or a machine exception.
A pointer to void can be converted to or from a pointer to any incomplete or object type. If a pointer to any incomplete or object type is converted to a pointer to void and back, the result compares equal to the original pointer.
An integral constant expression equal to 0, or such an expression cast to the void * type, is called a null pointer constant. If a null pointer constant is assigned to or compared for equality with a pointer, the constant is converted to a pointer of that type. Such a pointer is called a null pointer, and is guaranteed to compare unequal to a pointer to any object or function.
An array designator is automatically converted to a pointer to the array type, and the pointer points to the first element of the array.
Previous | Next | Contents | Index |
|