<< Previous | Index | Next >>

> ## 15. 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 a pointer to an integer
>     int (*a)();                // pointer to a function returning an integer

> 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.

> ### 15.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
>     int j;

>     j = 45;
>     p = &j;                // p now points to j

>     k = *p;                // k gets the value to which p points (k=45)
>     *p = 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

> ### 15.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

> ### 15.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

> ### 15.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

> ### 15.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

> ### 15.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 ){
>         ...
>     }

> ### 15.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

> ### 15.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;

>     j = 45;
>     p = &j;                // p now points to j

>     k = *p;                // k gets the value to which p points (k=45)
>     *p = 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

> ### 15.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.

> ### 15.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 15-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

Dynamic C User's Manual | << Previous | Index | Next>> | rabbit.com