1 Introduction to C

1.4 Operations and expressions

By means of computing, we often refer to arithmetic operations: addition, subtraction, multiplication, and division. C provides all these arithmetic operations for character, integer, and floating types. C also provides Boolean operations, and bitwise operations.

1.4.1 Arithmetic operations

Arithmetic operations

An arithmetic operation is an operation of two operands by operator, e.g., a+b.

Arithmetic operators include: * (multiply), / (divide), + (add), - (subtract), and % (modulus) for non-floating types.

Operands are values of of types: char, int, short, long, signed, unsigned, float, and double.

Table 1 summaries the arithmetic operations on the int type.

int a = 9, b = 3, result;
Table 1: Arithmetic operations
Operation Operator Syntax Usage example Result
Addition + a + b result = a + b 12
Subtraction a – b result = a – b 6
Multiplication * a*b result = a*b; 27
Divide / a / b result = a / b 3
Modulus % a % b result = a % b 0

Arithmetic expressions

An arithmetic expression (or algebraic expression) consists of constants, variables, arithmetic operators, and parenthesis, and constructed by the basic operations of form operand operator operand. For example, (a+b)*(a+1). This type of expression is also called infix expression, meaning that the operator is placed between operands.

When writing an arithmetic expression in source code program, like result = (a+b)*(a-b)/(8-4); The compiler will parse the right side expression, evaluate and convert it to a sequence of instructions to evaluate the expression. In this example, 8-4 will be evaluated to 4 at compile time, and a+b, a-b, (a+b)*(a-b), and dividing 4 are computed at runtime.

Result type of arithmetic operations

An arithmetic operation of two operands with the same data type gives a result of the operands’ data type. For example, int / int gives int, e.g., 5/2 gives 2. float / float gives float, e.g., 1.0/2.0 gives 0.5.

C allows operands of different types. An operation of two operands of different data types will do type conversion. Type conversion of operands changes the data type of one type to another data type. The type conversion is done from low to high in order of: char, int, long, float, double. That is, when the two operands have different data types, the lower type operand will be converted to the higher type value first and then do the operation. For example, 3 + 2.4 is evaluated as 3.0+2.4 = 5.4, in which int value 3 is converted to float type value 3.0. Similarly, 1.0/2 is evaluated as 1.0/2.0 = 0.5.

C provides forced conversion (also called type casting) by adding (data type) in front of a value or a variable. For example, (int) 1.0/2 will force to covert 1.0 to int value 1. So (int)1.0/2 will be evaluated as 1/2, which has value 0.

Example:

int a = 2.8;      // compilers will change 2.8 to 2, and assign 2 to variable a.
float b = 2.6;
int a = b;        // implicit casting, convert b to int at runtime, a will have value 2
int c = (int) b;  // explicit casting, convert at runtime, c have value 2
int d = a + b;    // implicitly cast a to float type, and add b, and then implicitly cast the result to int type value and assign to d, d will have value 4
float e = (float) a + b; // explicit cast a to float type, and add b, then assign result to e, e will have value 4.6 

Refer to code example arithmetics casting for the result of the conversions.

Overflow and underflow

An overflow happens when the result of an operation is out of range of the data type. When overflow happens, the operation result may not be correct.

For example, int a = 2147483647; int b = a+1; a has value 2147483647 = 231-1, b+1 = 231 = 2147483648. But this correct result is out of range of int type, so the actual value of b after the computing will not be 2147483648.

An underflow (or floating point underflow) happens when the operation produces a result, with absolute value smaller than the smallest positive floating number the of float type.

1.4.2 Logic operations

Relational operations

A relational operation compares two operands by a relational operator and returns 1 if true and 0 otherwise. For example, 10 > 2 is a relational operation, which returns 1.

Relational operators include: < (less), <= (less or equal to), > (bigger), >= (bigger or equal to), == (equal), != (not equal).

Table 2 gives examples of relational operations.

int a = 9, b = 3, result;
Table 2: Relational operations
Relational operator Meaning Syntax Usage example Result
< less than a < b result = a < b; 0
<= less than or equal to a <= b result = a <= b; 0
> greater than a > b result = a > b; 1
>= greater than or equal to a >= b result = a >= b; 1
== equal to a == b result = a == b; 0
!= not equal to a != b result = a != b; 1

Boolean expressions

A Boolean expression consists of constants, variables, arithmetic expressions, relational operators, and parenthesis, and constructed by the relational operations. A Boolean expression gives 1 if it is true and 0 otherwise.

A Boolean expression can be an arithmetic expression, that returns 0 (false) if the value of the arithmetic expression is zero, otherwise returns 1 (true).

The operands of a relational operation can be arithmetic expressions. For example, (a+b)*(a-b) > (c+d). It gives 1 if the runtime evaluation of the left side is bigger than the right side; otherwise 0.

Logical operations

A logical operation is an operations on Boolean expression operands with a logical operator.

Logical operators include: && (AND, gives 1 if and only if both operands are true), || (OR, gives 1 if and only if one of the operands is true), ! (NOT, gives 1 if and only if the operand is false).

Note that in a logic operation, a single value or an arithmetic expression will be treated as a Boolean expression. For example, a && b is equivalent to a != 0 && b != 0.

Table 3 gives examples of logical operations.

int x = 2, y = 3;
int a = (x == y), b = (x != y), result;
Table 3: Logical operations
Operation Meaning Syntax Usage example Result
&& AND a && b result = a && b; 0
|| OR a || b result = a || b; 1
! NOT !a result = !a; 1

Logic expressions

A logic expression is an expressions consisting of Boolean expressions, logic operators, parenthesis, and constructed by logic operations. It gives 1 if true and otherwise 0.

Example:

!(3 == 3)              => 0
(3 == 3) && (2 == 3)   => 0
(3 == 3) && !(2 == 3)  => 1
(3 == 3) || (2 == 3)   => 1
2 && 3                 => 1 because 2 and 3 will be valued as true (non-zero) 

Logic expressions are used to represent conditions in selection and repetition statements.

1.4.3 Bitwise operations

Bitwise operations

A bitwise operation operates on bit patterns, namely binary numbers at the level of their individual bits. Bitwise operations are primitive operations directly supported by processors.

Bitwise operators include: & (AND), | (OR), ^ (XOR), ~ (complement), << (shift left), >> (shift right).

The data types of operands of bitwise operations are unsigned data types including unsigned char, unsigned int, unsigned long. Every bit of the types are involved in an operation. The result of a bitwise operation is of the same type of its operands. If char, int, long types are are used, the left most sign bit will be used as a normal bit in bit operations.

Bitwise expressions

A bitwise expression consists of constants, variables, bitwise operators, and parenthesis, and constructed by bitwise operations.

Table 4 gives examples of bitwise operations.

unsigned int a = 60, b = 13, c;

Table 4: Bitwise operations
Bitwise operator Definition Usage example Result
& AND c = a & b; 12
| OR c = a | b; 61
^ XOR c = a ^ b; 49
~ Compliment c = ~a; 4294967235
<< Shift left c = a << 2; // shift left by 2 bits 240
>> Shift right c = a >> 2; // shift right by 2 bits 15

The following illustrates the results of Table 4 in binary format.

unsigned int a, b, c;
a = 60;      // a: 00000000 00000000 00000000 00111100
b = 13;      // b: 00000000 00000000 00000000 00001101
c = a & b;   // c: 00000000 00000000 00000000 00001100 
c = a | b;   // c: 00000000 00000000 00000000 00111101
c = a ^ b;   // c: 00000000 00000000 00000000 00110001 
c = ~a;      // c: 11111111 11111111 11111111 11000011 
c = a << 2;  // c: 00000000 00000000 00000000 11110000
c = a >> 2;  // c: 00000000 00000000 00000000 00001111

1.4.4 Unary Operators

C has three unary operators:

Unary operator Description Usage example
- unary minus, get the negative value of its operand -a
++ increase the operand variable by 1 a++;
decrease the operand variable by 1 a–;

The operand variables of ++ and – are of integer type values, e.g., char, int, long, etc.

Example:

int i = 1, j;
i++;     //  equivalent to i = i + 1;
++i;     //  equivalent to i = i + 1; 
i--;     //  equivalent to i = i -1;
--i;     //  equivalent to i = i -1;
j = i++; //  equivalent to j = i; i = i + 1;  
j = ++i; //  equivalent to i = i + 1; j = i;

1.4.5 Assignment operators

The assignment operator = is responsible for assigning (or setting) values to the variables in source code programs. C also supports a set of shorthand assignment operations combined with arithmetic and bitwise operations. Table 5 gives some examples of the shorthand assignment operations.

Table 5: Assignment operations
Operator Syntax Equivalent to
+= a += b; a = a + b;
-= a -= b; a = a - b;
*= a *= b; a = a * b;
/= a /= b; a = a / b;
%= a %= b; a = a % b;
&= a &= b; a = a & b;
^= a ^= b; a = a ^ b;
<<= a <<= b; a = a << b;
>>= a >>= b; a = a >> b;

1.4.6 Exercises

Self-quiz

Take a moment to review what you have read above. When you feel ready, take this self-quiz which does not count towards your grade but will help you to gauge your learning. Answer the questions posed below.

Go back