<< Previous | Index | Next >>

13. Operators

An operator is a symbol such as +, -, or & that expresses some kind of operation on data. Most operators are binary--they have two operands.

a + 10             // two operands with binary operator "add"

Some operators are unary--they have a single operand,

-amount            // single operand with unary "minus"

although, like the minus sign, some unary operators can also be used for binary operations.

There are many kinds of operators with operator precedence. Precedence governs which operations are performed before other operations, when there is a choice.

For example, given the expression

a = b + c * 10;

will the + or the * be performed first? Since * has higher precedence than +, it will be performed first. The expression is equivalent to

a = b + (c * 10);

Parentheses can be used to force any order of evaluation. The expression

a = (b + c) * 10;

uses parentheses to circumvent the normal order of evaluation.

Associativity governs the execution order of operators of equal precedence. Again, parentheses can circumvent the normal associativity of operators. For example,

a = b + c + d;             // (b+c) performed first
a = b + (c + d); // now c+d is performed first
int *a(); // function returning ptr to int
int (*a)(); // ptr to function returning int

Unary operators and assignment operators associate from right to left. Most other operators associate from left to right.

Certain operators, namely *, &, (), [], -> and . (dot), can be used on the left side of an assignment to construct what is called an lvalue. For example,

float x;
*(char*)&x = 0x17; //
low byte of x gets value

When the data types for an operation are mixed, the resulting type is the more precise.

float x, y, z;
int i, j, k;
char c;
z = i / x; //
same as (float)i / x
j = k + c; //
same as k + (int)c

By placing a type name in parentheses in front of a variable, the program will perform type casting or type conversion. In the example above, the term (float)i means the "the value of i converted to floating point."

The operators are summarized in the following pages.

13.1 Arithmetic Operators


+

Unary plus, or binary addition. (Standard C does not have unary plus.) Unary plus does not really do anything.


a = b + 10.5;           // binary addition
z = +y; // just for emphasis!


-

Unary minus, or binary subtraction.


a = b - 10.5;           // binary subtraction
z = -y; // z gets the negative of y


*

Indirection, or multiplication. As a unary operator, it indicates indirection. When used in a declaration, * indicates that the following item is a pointer. When used as an indirection operator in an expression, * provides the value at the address specified by a pointer.


int *p;                // p is a pointer to an integer
const int j = 45;
p = &j; // p
now points to j.
k = *p; // k
gets the value to which
// p points, namely 45.
*p = 25; // The integer to which p points gets 25.
// Same as j = 25, since p points to j.

Beware of using uninitialized pointers. Also, the indirection operator can be used in complex ways.


int *list[10]            // array of 10 pointers to integers
int (*list)[10] // pointer to array of 10 integers
float** y; // pointer to a pointer to a float
z = **y; // z
gets the value of y
typedef char **stp;
stp my_stuff; // my_stuff
is typed char**

As a binary operator, the * indicates multiplication.


a = b * c;               // a gets the product of b and c


/

Divide is a binary operator. Integer division truncates; floating-point division does not.


const int i = 18, const j = 7, k; float x;

k = i / j;                // result is 2;
x = (float)i / j; // result is 2.591...


++

Pre- or post-increment is a unary operator designed primarily for convenience. If the ++ precedes an operand, the operand is incremented before use. If the ++ operator follows an operand, the operand is incremented after use.


int i, a[12];
i = 0;
q = a[i++]; // q
gets a[0], then i becomes 1
r = a[i++]; // r
gets a[1], then i becomes 2
s = ++i; // i
becomes 3, then s = i
i++; // i
becomes 4

If the ++ operator is used with a pointer, the value of the pointer increments by the size of the object (in bytes) to which it points. With operands other than pointers, the value increments by 1.


--

Pre- or post-decrement. If the -- precedes an operand, the operand is decremented before use. If the -- operator follows an operand, the operand is decremented after use.


int j, a[12];
j = 12;
q = a[--j]; // j
becomes 11, then q gets a[11]
r = a[--j]; // j
becomes 10, then r gets a[10]
s = j--; // s = 10,
then j becomes 9
j--; // j
becomes 8

If the -- operator is used with a pointer, the value of the pointer decrements by the size of the object (in bytes) to which it points. With operands other than pointers, the value decrements by 1.


%

Modulus. This is a binary operator. The result is the remainder of the left-hand operand divided by the right-hand operand.


const int i = 13;
j = i % 10; // j
gets i mod 10 or 3
const int k = -11;
j = k % 7; // j
gets k mod 7 or -4

13.2 Assignment Operators


=

Assignment. This binary operator causes the value of the right operand to be assigned to the left operand. Assignments can be "cascaded" as shown in this example.


a = 10 * b + c;     // a gets the result of the calculation

a = b = 0;          // b gets 0 and a gets 0


+=

Addition assignment.


a += 5;             // Add 5 to a. Same as a = a + 5


-=

Subtraction assignment.


a -= 5;          // Subtract 5 from a. Same as a = a - 5


*=

Multiplication assignment.


a *= 5;         // Multiply a by 5. Same as a = a * 5


/=

Division assignment.


a /= 5;         // Divide a by 5. Same as a = a / 5


%=

Modulo assignment.


a %= 5;         // a mod 5. Same as a = a % 5


<<=

Left shift assignment.


a <<= 5;        // Shift a left 5 bits. Same as a = a << 5


>>=

Right shift assignment.


a >>= 5;        // Shift a right 5 bits. Same as a = a >> 5


&=

Bitwise and assignment.


a &= b;           // AND a with b. Same as a = a & b


^=

Bitwise XOR assignment.


a ^= b;          // XOR a with b. Same as a = a ^ b


|=

Bitwise or assignment.


a |= b;          // OR a with b. Same as a = a | b

13.3 Bitwise Operators


<<

Shift left. This is a binary operator. The result is the value of the left operand shifted by the number of bits specified by the right operand.


int i = 0xF00F;
j = i << 4; // j
gets 0x00F0

The most significant bits of the operand are lost; the vacated bits become zero.


>>

Shift right. This is a binary operator. The result is the value of the left operand shifted by the number of bits specified by the right operand:


int i = 0xF00F;
j = i >> 4; // j
gets 0xFF00

The least significant bits of the operand are lost; the vacated bits become zero for unsigned variables and are sign-extended for signed variables.


&

Address operator, or bitwise and. As a unary operator, this provides the address of a variable:


int x;
z = &x; // z
gets the address of x

As a binary operator, this performs the bitwise and of two integer (char, int, or long) values.


int i = 0xFFF0;
int j = 0x0FFF;
z = i & j; // z
gets 0x0FF0


^

Bitwise exclusive OR. A binary operator, this performs the bitwise XOR of two integer (8-bit, 16-bit or 32-bit) values.


int i = 0xFFF0;
int j = 0x0FFF;
z = i ^ j; // z
gets 0xF00F


|

Bitwise inclusive OR. A binary operator, this performs the bitwise or of two integer (8-bit, 16-bit or 32-bit) values.


int i = 0xFF00;
int j = 0x0FF0;
z = i | j; // z
gets 0xFFF0


~

Bitwise complement. This is a unary operator. Bits in a char, int, or long value are inverted:


int switches;
switches = 0xFFF0;
j = ~switches; // j
becomes 0x000F

13.4 Relational Operators


<

Less than. This binary (relational) operator yields a Boolean value. The result is 1 if the left operand is less than the right operand, and 0 otherwise.


if( i < j ){
body                   //
executes if i < j
}
OK = a < b;               // true when a < b


<=

Less than or equal. This binary (relational) operator yields a boolean value. The result is 1 if the left operand is less than or equal to the right operand, and 0 otherwise.


if( i <= j ){
body //
executes if i <= j
}
OK = a <= b; //
true when a <= b


>

Greater than. This binary (relational) operator yields a Boolean value. The result is 1 if the left operand is greater than the right operand, and 0 otherwise.


if( i > j ){
body //
executes if i > j
}
OK = a > b; //
true when a > b


>=

Greater than or equal. This binary (relational) operator yields a Boolean value. The result is 1 if the left operand is greater than or equal to the right operand, and 0 otherwise.


if( i >= j ){
body //
executes if i >= j
}
OK = a >= b; //
true when a >= b

13.5 Equality Operators


==

Equal. This binary (relational) operator yields a Boolean value. The result is 1 if the left operand equals the right operand, and 0 otherwise.


if( i == j ){
body //
executes if i = j
}
OK = a == b; // true when a = b

Note that the == operator is not the same as the assignment operator (=). A common mistake is to write


if( i = j ){
body
}

Here, i gets the value of j, and the if condition is true when i is non-zero, not when i equals j.


!=

Not equal. This binary (relational) operator yields a Boolean value. The result is 1 if the left operand is not equal to the right operand, and 0 otherwise.


if( i != j ){
body //
executes if i != j
}
OK = a != b; // true when a != b

13.6 Logical Operators


&&

Logical AND. This is a binary operator that performs the Boolean and of two values. If either operand is 0, the result is 0 (false). Otherwise, the result is 1 (true).


||

Logical OR. This is a binary operator that performs the Boolean or of two values. If either operand is non-zero, the result is 1 (true). Otherwise, the result is 0 (false).


!

Logical not. This is a unary operator. Observe that C does not provide a Boolean data type. In C, logical false is equivalent to 0. Logical true is equivalent to non-zero. The NOT operator result is 1 if the operand is 0. The result is 0 otherwise.


test = get_input(...);

if( !test ){
...
}

13.7 Postfix Expressions


( )

Grouping. Expressions enclosed in parentheses are performed first. Parentheses also enclose function arguments. In the expression


a = (b + c) * 10;

the term b + c is evaluated first.


[ ]

Array subscripts or dimension. All array subscripts count from 0.


int a[12];                // array dimension is 12
j = a[i]; // references the ith element


. (dot)

The dot operator joins structure (or union) names and subnames in a reference to a structure (or union) element.


struct {
int x;
int y;
} coord;
m = coord.x;


->

Right arrow. Used with pointers to structures and unions, instead of the dot operator.


typedef struct{
int x;
int y;
} coord;

coord *p; //
p is a pointer to structure
...
m = p->x; //
reference to structure element

13.8 Reference/Dereference Operators


&

Address operator, or bitwise and. As a unary operator, this provides the address of a variable:


int x;
z = &x; // z
gets the address of x

As a binary operator, this performs the bitwise and of two integer (char, int, or long) values.


int i = 0xFFF0;
int j = 0x0FFF;
z = i & j; // z
gets 0x0FF0


*

Indirection, or multiplication. As a unary operator, it indicates indirection. When used in a declaration, * indicates that the following item is a pointer. When used as an indirection operator in an expression, * provides the value at the address specified by a pointer.


int *p;                // p is a pointer to an integer
int j = 45;
p = &j; // p
now points to j.
k = *p; // k
gets the value to which
// p points, namely 45.
*p = 25; //
The integer to which p
//
points gets 25. Same as j = 25,
//
since p points to j.

Beware of using uninitialized pointers. Also, the indirection operator can be used in complex ways.


int *list[10]            // array of 10 ptrs to int
int (*list)[10] // ptr to array of 10 ints
float** y; // ptr to a ptr to a float
z = **y; // z
gets the value of y
typedef char **stp;
stp my_stuff; // my_stuff
is typed char**

As a binary operator, the * indicates multiplication.


a = b * c;               // a gets the product of b and c

13.9 Conditional Operators

Conditional operators are a three-part operation unique to the C language. The operation has three operands and the two operator symbols ? and :.


? :

If the first operand evaluates true (non-zero), then the result of the operation is the second operand. Otherwise, the result is the third operand.


int i, j, k;
...
i = j < k ? j : k;

The ? : operator is for convenience. The above statement is equivalent to the following.


if( j < k )
i = j;
else
i = k;

If the second and third operands are of different type, the result of this operation is returned at the higher precision.

13.10 Other Operators


(type)

The cast operator converts one data type to another. A floating-point value is truncated when converted to integer. The bit patterns of character and integer data are not changed with the cast operator, although high-order bits will be lost if the receiving value is not large enough to hold the converted value.


unsigned i; float x = 10.5; char c;
i = (unsigned)x; // i
gets 10;
c = *(char*)&x; // c
gets the low byte of x
typedef ... typeA;
typedef ... typeB;
typeA item1;
typeB item2;
...
item2 = (typeB)item1; //
forces item1 to be treated as a typeB


sizeof

The sizeof operator is a unary operator that returns the size (in bytes) of a variable, structure, array, or union. It operates at compile time as if it were a built-in function, taking an object or a type as a parameter.


typedef struct{
int x;
char y;
float z;
} record;
record array[100];
int a, b, c, d;
char cc[] = "Fourscore and seven";
char *list[] = { "ABC", "DEFG", "HI" };
#define array_size sizeof(record)*100 // number of bytes in array
a = sizeof(record); // 7
b = array_size; // 700
c = sizeof(cc); // 20
d = sizeof(list); // 6

Why is sizeof(list) equal to 6? list is an array of 3 pointers (to char) and pointers have two bytes.

Why is sizeof(cc) equal to 20 and not 19? C strings have a terminating null byte appended by the compiler.


,

Comma operator. This operator, unique to the C language, is a convenience. It takes two operands: the left operand--typically an expression--is evaluated, producing some effect, and then discarded. The right-hand expression is then evaluated and becomes the result of the operation.

This example shows somewhat complex initialization and stepping in a for statement.


for( i=0,j=strlen(s)-1; i<j; i++,j--){
...
}

Because of the comma operator, the initialization has two parts: (1) set i to 0 and (2) get the length of string s. The stepping expression also has two parts: increment i and decrement j.

The comma operator exists to allow multiple expressions in loop or if conditions.

The table below shows the operator precedence, from highest to lowest. All operators grouped together have equal precedence.
Table 13-1. Operator Precedence
Operators
Associativity
Function
() [] -> . left to right member
! ~ ++ -- (type) * & sizeof right to left unary
* / % left to right multiplicative
+ - left to right additive
<< >> left to right bitwise
< <= > >= left to right relational
== != left to right equality
& left to right bitwise
^ left to right bitwise
| left to right bitwise
&& left to right logical
|| left to right logical
? : right to left conditional
= *= /= %= += -= <<= >>= &= ^= |= right to left assignment
, (comma) left to right series


<< Previous | Index | Next >>
Z-World, Inc.
www.zworld.com
Phone: 1.530.757.3737
Fax: 1.530.757.3792
Rabbit Semiconductor
www.rabbitsemiconductor.com
Phone: 1.530.757.8400
Fax: 1.530.757.8402