C operators and expressions
The C programming language provides a rich set of operators that you can use in manipulating data.
Operators are symbols like "+" and "=" that are used in conjunction with variables and constants in order to create expressions. Expressions are C statements that which when evaluated, will produce data.
I'll group the operators according to their use below. Now, even though we'll discuss assignment operators in detail further down below, please note that the basic assignment operator is the equal sign "=". This is slightly different from the equality symbol in Mathematics.
Therefore in the sample code below, we are not testing whether var is equal to 10 but we are assigning the value 10 to the variable var.
var = 10;
We'll look at first the so-called "arithmetic" operators which you may be well familiar with.
The operators above are also considered as "binary" operators. Please don't think that they're used in manipulating binary data. The term binary simply means that these operators need two values in order to work properly. See examples below:
x = 2 + 3; x = 10 * 5; x = 18 - 5; x = 5 / 4;
Note from the examples above that there is a value on the left and on the right of the arithmetic operators used. These are actually called "operands". Operands can also be variables. Furthermore, you can even put multiple operators and operands in one line of code. See below for more examples.
x = 2 + 3 * 5; y = x * x; z = 120 * 5 - x;
Now you might be thinking, if there are multiple operators in one line, what is the order in which they are evaluated? Luckily C follows the convention in Mathematics. To recall, here's the order of operations to be taken, this is normally known as the precedence rule.
- Expressions inside parentheses will be evaluated first
- then Terms with exponents
- then Multiplication, division and modulo
- and finally, Addition and subtraction
That's pretty straightforward isn't it. I'll leave it to you to experiment with this.
For those who don't know yet, modulo is used to get the remainder of a division operation. Like 10 % 3 will give you 1. That's because 10 / 3 = 3 remainder 1.
Relational and Logical operators
The relational and logical operators are used for comparing two values. These are again considered as binary operators requiring two operands in order to function properly.
We will get into discussing conditional statements in C later on as part of the topic "Controlling program flow" where we'll discuss the keywords if, switch and loops.
For now, just familiarize yourself with the operators and their meaning below. Also note that relational and logical operators are lower in precedence than arithmetic operators. In order words, given:
x < y + 5
the compiler will interpret this as
x < (y + 5)
In other words, y + 5 will be evaluated first and then compare the result with x.
Below is a table showing the relational and logical operators arranged in order of precedence. Symbols at the top has higher precedence than symbols at the bottom.
less than or equal
greater than or equal
is not equal
Bitwise operators are used to perform bit manipulations. There are six such operators used in C and are shown in the table below.
As a short review of bitwise operations, let's recall that data at the lowest level is represented by the computer in binary digits or "bits". Data can only be represented using digits 1 and 0. For instance, the decimal value 65 will be stored in the computer as 01000001. This can also be represented in hexadecimal ("base 16") notation as 0x41.
Therefore bitwise operations refer to operations that affect the value of a bit or bits that represent data. For example, the expression below will have the effect of converting the decimal value 65 into decimal value 130. Or in hexadecimal, 0x41 is converted into 0x82.
65 << 1
So what's happened here? So given the decimal 65, which is represented in binary as:
0 1 0 0 0 0 0 1
Note that I've only shown the lower 8 bits of the number. In reality, the number will be stored in the computer using either 32, 16 or 8 bits depending on the data type. When the left shift is applied to it using the "<<" operator. All the bits are moved to the left by one location. Since there are only so many bits that can hold the number, doing the left shift would have the effect of making the left-most bit to fall off and the right most bit location to be empty.
So if, for instance, the value 65 above is of type char, then there are only 8 bit locations available to store it. Thus with the left shift of 1 bit location, here's what will happen.
0 1 0 0 0 0 0 1 0
The left-most zero will be dropped, then the next bit, which is 1, will take its place and will become the new left-most bit. Then the next zero and all the other zeros after that will move to the left in the same manner.
Because the bits move in that fashion, a new blank bit location will appear at the right-most bit. This empty location will be taken by a value of zero. It's like as if this new zero on the right has pushed all the bits to the left dropping that left-most zero off in the process.
What you're left with is:
1 0 0 0 0 0 1 0
Which is 130 in decimal and 0x82 in hexadecimal.
Assignment operators are operators used to assign the value of an expression in a variable or constant. We've seen that equal sign operator which as we know very well assigns the value on the right to the identifier on the left. There are however other operators you can use, like "+=", that's "plus" and "equal" signs together.
The "+" symbol can be any of the above binary operators like -, <<, *, etc. This type of assignment operator is used usually to increment or decrement a variable. Let's say you have an expression like this:
x = x + 5;
We know you are assigning x + 5 to the variable x. This can be written as:
x += 5;
The expression above would usually be read as "increment x by 5". Again, this applies to the other binary operators above including the bitwise operators. So you can have the following examples:
x *= 100; y <<= 1; z &= 0xff;
Unary operators are operators that require only one operand. This will include the following:
increment by one
decrement by one
The logical NOT will make a non-zero value zero and will make a zero value 1. For example:
!5 means 0
!0 means 1
The bitwise NOT will reverse the bits of a value. So for example:
~7 means -8
This bitwise NOT operation can be tricky and will require you to review your one's and two's complement to better understand them.
The increment and decrement operators are similar to += and -= assignment operators above. This time though, they always add or subtract one from the variable.
The * and & operators here, which can be confused with the multiplication and bitwise AND operators, are used in an advanced variable called the pointer. We'll have fun with pointers later on but not now.
All this might be quite a lot to digest for now, so I'll stop here and move on to other more exciting topics next time. As an exercise for you, what would happen if the result of an expression does not match the target variable ("the variable on the left side of the equation"). Like the example below where by x is an integer but 5 / 4 will yield 1.25 which is a float?
int x = 5 / 4;
Or what about this next one, where by the result will be 36100 which is more than what can be stored in a char type variable?
char y = 190;
z = y * y;