Basic Operations

The C language provides a number of basic operations. These operations form the basic building blocks of most C expressions. All of the operators in C have a particular precedence order Parentheses can be used to explicitly group operations and force C to evaluate them in a particular another.

Assignment Operation

The first operation you will ever use is the assignment operation. The assignment operation, denoted by = assigns the value of the expression on the right to the variable on the left. For example, the expression x = 5 puts the value 5 in the variable x. You can have any expression on the right-hand-side so x = 7 * 2 will result in x containing the value 14. It is worth noting, however, that an assignment is also an expression in its own right. When an assignment expression is evaluated, the result of the expression is that value that was assigned. Therefore, the expression x = (y = 7) will result in both x and y being assigned the value 7.

Mathematical Operations

C provides six basic mathematical operations:

Symbol Description Example Expression Result
+ addition 7 + 3 10
- subtraction 7 - 3 4
- negation -(7 + 3) -10
* multiplication 7 * 3 21
/ division 7 / 3 2
% modulus 7 % 3 1

Most of these do exactly what you would expect them to do. A little care is needed when working with division and modulus. For division, if both operands are integers, it gives you the integer part of the division and throws away the remainder; if one operand is a floating-point type, it does a floating-point division. Modulus requires a little bit of care because (-x) % y is equivalent to -(x % y) which is not the same as in math.

Increment and Decrement Operatiors

Sometimes it is very useful to add or subtract a number from a variable and assign it back to the original variable. While we could write x = x + 7 every time, this can be cumbersome especially if you have a long variable name. Fortunately, C provides a nice little shortcut, the += family of operators. For each mathematical operator above as well as each bitwise logical operators below, there is another operator of the form “#=” where “#” is one of these operators. So instead of writing x = x + 7 all the time, you can just write x += 7. More formally, if # is one of these operators, a #= b is equivalent to a = a # b.

In the case of adding or subtracting 1, it gets even better. The C language provides four operators: -- and ++ that do exactly that. Why did I say four operators and list only two? Because they are different operators depending on whether you place them before the variable or after. In either case, the variable gets incremented (or decremented) by 1. However, the expression x++ evaluates to the value of x before it was incremented and the value of the expression ++x is the value of x after it gets incremented. These operators are called the post- or pre-increment and post- or pre-decrement operators. These can be summed up in the following table:

Initial value of x Expression Final value of x Value of expression
5 ++x 6 6
5 x++ 6 5
5 --x 4 4
5 x-- 4 5

Cast Operations

In order to allow for conversion from one type to another, C provides a cast operation. You cast data of one type to another by putting (type) in front of the expression. For instance, if you had two integers x and y and you wanted to do a floating-point division, you could do x / (float)y which would cast the value of y to type float before performing the division. Or, if you had two variables a and b of type short and you wanted to multiply them while making sure you don’t get overflow, you could do a * (int)b which would guarantee that an int multiplication and not a short multiplication is performed.

When you cast to and from float, C will automatically perform the encoding conversion for you. However, you have to be careful as C does not round and when you convert from a floating-point type to an integer type; the fractional part is simply truncated.

Bit-wise Logical Operations

C also provides ways to work with integer data types in a bitwise or logical fashion. The operations described here are bit-wise meaning that it is a boolean operation applied to each bit in the variable independently. The table below describes the four bit-wise logical operation. Note that the expressions below are not technically correct as C would interpret them in base-10. I used binary for ease of reading.

Symbol Description Example Expression Result
| bit-wise OR 110 | 011 111
& bit-wise AND 110 & 011 010
^ bit-wise XOR 110 ^ 011 101
~ bit-wise NOT !110 001

Shift Operations

Another facility C provides for working with binary data are called the shift operators. These operators shift the data to the right or left a certain number of bits. The table below describes these operators:

Symbol Description Example Expression Result
<< left-shift 110 << 2 11000
>> right-shift 110 >> 1 11

When using the right-shift operator, you have to be mindful of whether the data being shifted is of a signed or unsigned type. If the data is unsigned, then a right-shift operation will add zeros to left to pad the data back to its original size. If the data is signed, the right-shift operation will pad the data using whatever was in the left-most bit of the original data. The reason for this is that it guarantees that negative numbers remain negative when shifted so that x >> y is equivalent to x / 2^y.

Logical and Comparison Operations

C also provides a number of comparison operations and logical operations that are not bit-wise. We will use these much more when we talk about control flow, but we may as well introduce them here. Each of these comparison operations evaluates to zero if the comparison fails and some non-zero value if the comparison succeeds. The exact non-zero value that results from a failed comparison is implementation-dependent.

Symbol Description Example Expression Result
< less than 5 < 2 0
<= less than or equal to 2 <= 2 nonzero
> greater than 3 < 3 0
>= greater than or equal to 3 <= 8 nonzero
== equal 5 == 8 0
!= not equal 5 != 8 nonzero

Notice that == and = are not the same. One refers to a comparison operation and the other refers to assignment. This can get you into quite a bit of trouble by getting these two mixed up.

I observed above, and will reiterate here, that data types matter when performing comparison operations. An unsigned type will always be greater than or equal to zero even if that same binary value in two’s compliment represents a negative number. Many compilers will also throw warnings if attempt to compare two variables one of which is signed and the other is not.

Along with the above comparison operations, C has three logical operators that do not act in a bit-wise fashion. Instead, they act on the basis of whether the arguments are zero or nonzero. As you would imagine, these are usually used in concert with the comparison operations described above.

Symbol Description Example Expression Result
|| OR (6 < 5) || (5 < 6) nonzreo
&& AND 0 && 6 0
! NOT !0 nonzero