Expressions and Operators

1.5 Expressions and Operators

An expression is a combination of operators and operands. In the simplest case, an expression consists simply of a constant, a variable, or a function call. Expressions can also serve as operands, and can be joined together by operators into more complex expressions.

Every expression has a type and, if the type is not void, a value. Some examples of expressions follow:

4 * 512  // Type: int  
printf("An example!\n")  // Type: int 
1.0 + sin(x)  // Type: double
srand((unsigned)time(NULL))  // Type: void
(int*)malloc(count*sizeof(int)) // Type: int *

In expressions with more than one operator, the precedence of the operators determines the grouping of operands with operators. The arithmetic operators *, /, and %, for example, take precedence over + and -. In other words, the usual rules apply for the order of operations in arithmetic expressions. For example:

4 + 6 * 512  // equivalent to 4 + (6 * 512)

If a different grouping is desired, parentheses must be used:

(4 + 6) * 512

Table 1-8 lists the precedence of operators.

Table 1-8. Precedence of operators

Priority

Operator

Grouping

1

() [] -> .

left to right

2

! ~ ++ -- + - (type) * & sizeof

right to left

3

* / %

left to right

4

+ -

left to right

5

<< >>

left to right

6

< <= > >=

left to right

7

== !=

left to right

8

&

left to right

9

^

left to right

10

|

left to right

11

&&

left to right

12

||

left to right

13

?:

right to left

14

= += -= *= /= %= &= ^= |= <<= >>=

right to left

15

,

left to right

If two operators have equal precedence, then the operands are grouped as indicated in the "Grouping" column of Table 1-8. For example:

2 * 5 / 3  // equivalent to (2 * 5) / 3

Operators can be unary or binary: a unary operator has one operand, while a binary operator has two. This distinction is important for two reasons:

         All unary operators have the same precedence.

         The four characters -, +, *, and & can represent unary or binary operators, depending on the number of operands.

Furthermore, C has one ternary operator: the conditional operator ?: has three operands.

The individual operators are briefly described in Table 1-9 through Table 1-16 in the following sections. The order in which the operands are evaluated is not defined, except where indicated. For example, there's no guarantee which of the following functions will be invoked first:

f1() + f2() // Which of the two functions is 
 // called first is not defined.

1.5.1 Arithmetic Operators

Table 1-9. The arithmetic operators

Operator

Meaning

Example

Result

*

Multiplication

x * y

The product of x and y.

/

Division

x / y

The quotient of x by y.

%

Modulo division

x % y

The remainder of the division x / y.

+

Addition

x + y

The sum of x and y.

-

Subtraction

x - y

The difference of x and y.

+ (unary)

Positive sign

+x

The value of x.

- (unary)

Negative sign

-x

The arithmetic negation of x.

++

Increment

++x
x++

x is incremented (x=x+1). The prefixed operator (++x) increments the operand before it is evaluated; the postfixed operator (x++) increments the operand after it is evaluated.

--

Decrement

--x
x--

x is decremented (x=x-1). The prefixed operator (--x) decrements the operand before it is evaluated; the postfixed operator (x--) decrements the operand after it is evaluated.

The operands of arithmetic operators may have any arithmetic type. Only the % operator requires integer operands.

The usual arithmetic conversions may be performed on the operands. For example, 3.0/2 is equivalent to 3.0/2.0. The result has the type of the operands after such conversion.

Note that the result of division with integer operands is also an integer! For example:

6 / 4  //  Result:  1 
6 % 4  //  Result:  2 
6.0 / 4.0  //  Result: 1.5

The increment operator ++ (and analogously, the decrement operator --) can be placed either before or after its operand. A variable x is incremented (i. e., increased by 1) both by ++x (prefix notation) and x++ (postfix notation) . The expressions nonetheless yield different values: the expression ++x has the value of x increased by 1, while the expression x++ yields the prior, unincremented value of x.

Because the operators ++ and -- perform an assignment, their operand must be an lvalue; i. e., an expression that designates a location in memory, such as a variable.

The operators ++, --, + (addition), and - (subtraction) can also be used on pointers. For more information on pointers and pointer arithmetic, see Section 1.10.

1.5.2 Assignment Operators

Assignments are performed by simple and compound assignment operators, as shown in Table 1-10.

Table 1-10. Assignment operators

Operator

Meaning

Example

Result

=

Simple assignment

x = y

Assign the value of y to x

op=

Compound assignment

x += y

x op= y is equivalent to x = x op (y) (where op is a binary arithmetic or binary bitwise operator)

The left operand in an assignment must be an lvalue; i. e., an expression that designates an object. This object is assigned a new value.

The simplest examples of lvalues are variable names. In the case of a pointer variable ptr, both ptr and *ptr are lvalues. Constants and expressions such as x+1, on the other hand, are not lvalues.

The following operands are permissible in a simple assignment (=):

         Two operands with arithmetic types

         Two operands with the same structure or union type

         Two pointers that both point to objects of the same type, unless the right operand is the constant NULL

If one operand is a pointer to an object, then the other may be a pointer to the "incomplete" type void (i. e., void *).

If the two operands have different types, the value of the right operand is converted to the type of the left operand.

An assignment expression has the type and value of the left operand after the assignment. Assignments are grouped from right to left. For example:

a = b = 100;  // equivalent to  a=(b=100); 
 // The value 100 is assigned to b and a.

A compound assignment has the form x op= y, where op is a binary arithmetic operator or a binary bitwise operator. The value of x op (y) is assigned to x. For example:

a *= b+1;  // equivalent to  a = a * (b + 1);

In a compound assignment x op= y, the expression x is only evaluated once. This is the only difference between x op= y and x = x op (y).

1.5.3 Relational Operators and Logical Operators

Every comparison is an expression of type int that yields the value 1 or 0. The value 1 means "true" and 0 means "false." Comparisons use the relational operators listed in Table 1-11.

Table 1-11. The relational operators

Operator

Meaning

Example

Result: 1 (true) or 0 (false)

<

less than

x < y

1 if x is less than y

<=

less than or equal to

x <= y

1 if x is less than or equal to y

>

greater than

x > y

1 if x is greater than y

>=

greater than or equal to

x >= y

1 if x is greater than or equal to y

==

equal to

x == y

1 if x is equal to y

!=

not equal to

x != y

1 if x is not equal to y. In all other cases, the expression yields 0.

The following operands are permissible for all relational operators:

         Two operands with real arithmetic types. The usual arithmetic conversions may be performed on the operands.

         Two pointers to objects of the same type.

The equality operators == and != can also be used to compare complex numbers. Furthermore, the operands may also be pointers to functions of the same type. A pointer may also be compared with NULL or with a pointer to void. For example:

int cmp, *p1, *p2;
. . .
cmp = p1 < p2; // if p1 is less than p2, then cmp = 1; 
 // otherwise cmp = 0.

1.5.4 Logical Operators

The logical operators, shown in Table 1-12, can be used to combine the results of several comparison expressions into one logical expression.

Table 1-12. The logical operators

Operator

Meaning

Example

Result: 1 (true) or 0 (false)

&&

logical AND

x && y

1 if both x and y are not equal to 0

||

logical OR

x || y

1 if either or both of x and y is not equal to 0

!

logical NOT

!x

1 if x equals 0. In all other cases, the expression yields 0.

The operands of logical operators may have any scalar (i. e., arithmetic or pointer) type. Any value except 0 is interpreted as "true"; 0 is "false."

Like relational expressions, logical expressions yield the values "true" or "false"; that is, the int values 0 or 1:

!x || y  // "(not x) or y" yields 1 (true)
   // if x == 0 or y != 0

The operators && and || first evaluate the left operand. If the result of the operation is already known from the value of the left operand (i. e., the left operand of && is 0 or the left operand of || is not 0), then the right operand is not evaluated. For example:

i < max  &&  scanf("%d", &x) == 1

In this logical expression, the function scanf() is only called if i is less than max.

1.5.5 Bitwise Operators

There are six bitwise operators, described in Table 1-13. All of them require integer operands.

Table 1-13. The bitwise operators

Operator

Meaning

Example

Result (for each bit position)

&

bitwise AND

x & y

1, if 1 in both x and y

|

bitwise OR

x | y

1, if 1 in either x or y, or both

^

bitwise exclusive OR

x ^ y

1, if 1 in either x or y, but not both

~

bitwise NOT

~x

1, if 0 in x

<<

shift left

x << y

Each bit in x is shifted y positions to the left

>>

shift right

x >> y

Each bit in x is shifted y positions to the right

The logical bitwise operators, & (AND), | (OR), ^ (exclusive OR), and ~ (NOT) interpret their operands bit by bit: a bit that is set, i. e., 1, is considered "true"; a cleared bit, or 0, is "false". Thus, in the result of z = x & y, each bit is set if and only if the corresponding bit is set in both x and y. The usual arithmetic conversions are performed on the operands.

The shift operators << and >> transpose the bit pattern of the left operand by the number of bit positions indicated by the right operand. Integer promotions are performed beforehand on both operands. The result has the type of the left operand after integer promotion. Some examples are:

int  x = 0xF, result; 
result = x << 4; // yields 0xF0
result = x >> 2; // yields  0x3

The bit positions vacated at the right by the left shift << are always filled with 0 bits. Bit values shifted out to the left are lost.

The bit positions vacated at the left by the right shift >> are filled with 0 bits if the left operand is an unsigned type or has a non-negative value. If the left operand is signed and negative, the left bits may be filled with 0 (logical shift) or with the value of the sign bit (arithmetic shift), depending on the compiler.

1.5.6 Memory Accessing Operators

The operators in Table 1-14 are used to access objects in memory. The terms used here, such as pointer, array, structure, etc., are introduced later under Section 1.10.

Table 1-14. Memory accessing operators

Operator

Meaning

Example

Result

&

Address of

&x

A constant pointer to x

*

Indirection

*p

The object (or function) pointed to by p

[ ]

Array element

x[i]

*(x+i), the element with index i in the array x

.

Member of a structure or union

s.x

The member named x in the structure or union s

->

Member of a structure or union

p->x

The member named x in the structure or union pointed to by p

The operand of the address operator & must be an expression that designates a function or an object. The address operator & yields the address of its operand. Thus an expression of the form &x is a pointer to x. The operand of & must not be a bit-field, nor a variable declared with the storage class specifier register.

The indirection operator * is used to access an object or a function through a pointer. If ptr is a pointer to an object or function, then *ptr designates the object or function pointed to by ptr. For example:

int  a, *pa;  // An int variable and a pointer to int. 
 
pa  = &a;  // Let pa point to a. 
*pa = 123;  // Now equivalent to  a = 123;

The subscript operator [] can be used to address the elements of an array. If v is an array and i is an integer, then v[i] denotes the element with index i in the array. In more general terms, one of the two operands of the operator [] must be a pointer to an object (e. g., an array name), and the other must be an integer. An expression of the form x[i] is equivalent to (*(x+(i))). For example:

float  a[10], *pa; // An array and a pointer.
pa = a;  // Let pa point to a[0].

Since pa points to a[0], pa[3] is equivalent to a[3] or *(a+3).

The operators . and -> designate a member of a structure or union. The left operand of the dot operator must have a structure or union type. The left operand of the arrow operator is a pointer to a structure or union. In both cases, the right operand is the name of a member of the type. The result has the type and value of the designated member.

If p is a pointer to a structure or union and x is the name of a member, then p->x is equivalent to (*p).x, and yields the member x of the structure (or union) to which p points.

The operators . and ->, like [], have the highest precedence, so that an expression such as ++p->x is equivalent to ++(p->x).

1.5.7 Other Operators

The operators in Table 1-15 do not belong to any of the categories described so far.

Table 1-15. Other operators

Operator

Meaning

Example

Result

()

Function call

pow(x,y)

Execute the function with the arguments x and y

(type)

Cast

(long)x

The value of x with the specified type

sizeof

Size in bytes

sizeof(x)

The number of bytes occupied by x

?:

Conditional evaluation

x?y:z

If x is not equal to 0, then y, otherwise z

 
,

Sequence operator

x,y

Evaluate x first, then y

A function call consists of a pointer to a function (such as a function name) followed by parentheses () containing the argument list, which may be empty.

The cast operator can only be used on operands with scalar types! An expression of the form (type)x yields the value of the operand x with the type specified in the parentheses.

The operand of the sizeof operator is either a type name in parentheses or any expression that does not have a function type. The sizeof operator yields the number of bytes required to store an object of the specified type, or the type of the expression. The result is a constant of type size_t.

The conditional operator ?: forms a conditional expression. In an expression of the form x?y:z, the left operand x is evaluated first. If the result is not equal to 0 (in other words, if x is "true"), then the second operand y is evaluated, and the expression yields the value of y. However, if x is equal to 0 ("false"), then the third operand z is evaluated, and the expression yields the value of z.

The first operand can have any scalar type. If the second and third operands do not have the same type, then a type conversion is performed. The type to which both can be converted is the type of the result. The following types are permissible for the second and third operands:

         Two operands with arithmetic types.

         Two operands with the same structure or union type, or the type void.

         Two pointers, both of which point to objects of the same type, unless one of them is the constant NULL. If one operand is an object pointer, the other may be a pointer to void.

The sequence or comma operator , has two operands: first the left operand is evaluated, then the right. The result has the type and value of the right operand. Note that a comma in a list of initializations or arguments is not an operator, but simply a punctuation mark!

1.5.7.1 Alternative notation for operators

The header file iso646.h defines symbolic constants that can be used as synonyms for certain operators, as listed in Table 1-16.

Table 1-16. Symbolic constants for operators

Constant

Meaning

 

Constant

Meaning

 

Constant

Meaning

and
&&

 

bitand
&

 

and_eq
&=
or
||

 

bitor
|

 

or_eq
|=
not
!

 

xor
^

 

xor_eq
^=

 

 

 

compl
~

 

not_eq
!=
 

 



C Pocket Reference
C Pocket Reference
ISBN: 0596004362
EAN: 2147483647
Year: 2002
Pages: 29

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net