Arithmetic operators:
These operators are used to perform arithmetic operations.
The arithmetic operators are: +, -, *, / and %. The operations performed by
these operators are well known to us. Now, go through the following program and
predict the output. After this, execute the program and check the result.
#include<stdio.h>
main()
{
int a=10,b=20,c;
c=a+5-b/4*2;
printf("a=%d\tb=%d\tc=%d\n",a,b,c);
}
It is ambiguous for us to expect the output of the
assignment expression c=a+5-b/4*2, so does the compiler. In order to eliminate
such ambiguities precedence of the operator was introduced. Within the five
arithmetic operators available, the following is the order of precedence i.e., when
multiple operators occur in same statement, the compiler computes the operation
based upon the precedence of the operator.
+ - -> lower precedence
* / % ->
higher precedence
In, the expression c=a+5-b/4*2, / operator is of highest
precedence followed by *, - and +. Hence, the operators and operands of this
expression are grouped as c=(a+(5-((b/4)*2))). b/4 is computed first and the
result is multiplied with 2, which is subtracted from 5, which is in turn added
with a. After all the operations are performed, the result is assigned to c.
Consider the following program.
#include<stdio.h>
main()
{
int a=10,b=20;
b=a*b/a=b;
printf("a=%d\tb=%d\n",a,b);
}
In this, the expression b=a*b/a=b consists of the operators *,
/ and =. Out of these operators, * and / have same precedence. Also, there are
two assignment operators. The compiler now follows associativity of the
operators. Associativity gives the orientation in which the compiler should start
performing the operation with the given operators on the given operands. The
expression is evaluated as: b=((a*b)/(a=b)) in left-to-right fashion i.e.,
first a*b is evaluated, then a=b and then both the results are divided. At
last, the result is assigned to b.
Click here to get the precedence and associativity table of
operators in C language.
*Remember that modulo
division is not possible for real datatypes.
Relational operators:
Relational operators are used for comparison and the result is
given as 0 for false and 1 for true. The relational operators in C language are
<,<=,>,>=,== and !=. The functionality of all these operators are
well known. Execute the following program and check the output.
#include<stdio.h>
main()
{
char ch;
int x=5;
unsigned int y=5;
int a=5.5;
float b=5.5;
int c;
c=a==b;
printf("c=%d\n",c);
c=x>y;
printf("c=%d\n",c);
ch='B';
c=ch>'A';
printf("c=%d\n",c);
}
In the program mentioned above, we have comparisons between
variables of different datatypes. The variable x stores the integer value 5. The
variable y also stores 5, the difference is the MSB in x is used for
representing the sign but not the MSB of y. Though the variable a is of integer
datatype, we are explicitly storing a real value into it. The variable b is of
float type and 5.5 is stored into it. Observe that data from different
datatypes are being compared in the latter statements.
In order to compare data of different datatypes, data is
“type casted”. When compiling the above program, the compiler itself typecasts
the data, which is called implicit type casting. On the other hand, if the
programmer typecasts the data, it is called explicit type casting. The concept
of typecasting is discussed in latter sections. As of now, just assume that
type casting is converting one data type to the other.
Logical operators:
Logical AND (&&), Logical OR (||) and Logical NOT
(!) are the three logical operators in C language. Execute the following
program to know these logical operators.
#include<stdio.h>
main()
{
int a=0,b=10,c,d;
d=a&&b;
printf("AND:d=%d\n",d);
d=a||b;
printf("OR:d=%d\n",d);
d=!a;
printf("NOT:d=%d\n",d);
if((c=a&&b)&&(d=a||b))
printf("In if block..\n");
else
printf("In else block..\n");
}
*Note that any non-zero value (even if it is negative) is
considered as true and only zero is considered as false. Now, execute the following program and check the output.
#include<stdio.h>
main()
{
int a=20,b=-10,c,=0,d;
d=(a=b)||(b=c)||(c=a);
printf("a:%d\tb:%d\tc:%d\td:%d\n");
d=(a=b)&&(b=c)&&(c=a);
printf("a:%d\tb:%d\tc:%d\td:%d\n");
}
In this program, the outputs are not according to the
expectations. Because, the gcc compiler omits executing all other conditions
when any one of the conditions is false for AND and when any one of the
conditions is true for OR.
In the expression d=(a=b)||(b=c)||(c=a), the expression a=b
is evaluated first, which results in a non-zero value, hence true. Therefore,
the other two expression b=c and c=a are omitted, as the complete expression
results a non-zero value irrespective of other conditions.
In the expression d=(a=b)&&(b=c)&&(c=a), a=b
results in a non-zero value, which is true. Then the compiler moves to next
condition b=c, which results in a zero value, which is false. Hence, the
compiler skips the expression c=a, as the complete AND results in zero
irrespective of other conditions.
Bitwise operators:
As far as embedded systems are concerned, bitwise operators
play a major role. The bitwise operators present in C are
&,|,^,<<,>> and ~. We
are very familiar with the operations of these bitwise operators. Note that
bitwise operations cannot be performed on real values.
Bitwise AND (&), OR (|), and XOR (^) performs respective
operations on every single bit of the given data. The left shift operator (>>)
and the right shift operator (<<) shift the bits of the given data. The complement
operator (~) performs bitwise complement of the given data. Execute the following
program and predict the output before executing it. Compare the expected
results with the output produced after execution.
#include<stdio.h>
main()
{
int a=20,b=-100,c=0,d;
printf("a>>2:%d\n",a>>2);
printf("b>>3:%d\n",b>>3);
printf("b&-1:%d\n",b&-1);
printf("a|-1:%d\n",a|-1);
printf("a&0:%d\n",a&0);
printf("b|0:%d\n",b|0);
printf("a&(1<<4):%d\n",a&(1<<4));
printf("(a<<4)&1:%d\n",(a<<4)&1);
printf("1<<35:%d\n",1<<35);
printf("1>>35:%d\n",1>>35);
}
Points to remember about bitwise operators:
*Remember that any of the bitwise operators does not affect
the value contained by the operators.
*Bitwise AND (&) with -1 always results in second
operand.
*Any number is reduced by half, for every right shift.
Now, checkout the following program.
#include<stdio.h>
main()
{
int a=20,b=100,c=0,d;
printf("-30>>1:%d\n",-30>>1);
printf("-31>>1:%d\n",-31>>1);
printf("-32>>1:%d\n",-32>>1);
}
The output of this program is -16 and -16 for both the
expression -31>>1 and -32>>1. Recollect that negative numbers are stored
in their respective 2s complement format. Go through the following explanation
and observe that the LBS in -31>>1 and -32>>1 goes out of the 8-bit
limit of the binary representation. (For easy representation, only 8 bits were
considered, which can be extrapolated to 32 bits perfectly). Observe that -30>>1
can be converted to -15, by applying 2s complement on the bits.
Now, check out the following program that illustrates complement operator (~). The complement of ‘a’ here is fetched as a negative value by
the compiler, as the MSB is 1 in the result. Hence, the output.
In complement, the result can be expected using the
equation: ~b=-b-1
#include<stdio.h>
main()
{
int a=20,b;
b=~a;
printf("a:%d\tb:%d\n",a,b);
}
sizeof operator:
sizeof is the operator that gives the size of the given data
in bytes. Execute the following program and check the output.
#include<stdio.h>
main()
{
int a=20,b=100,c=0,d;
d=sizeof(a);
printf("%d\n",d);
d=sizeof(int);
printf("%d\n",d);
d=sizeof(-100);
printf("%d\n",d);
d=sizeof(1.0);
printf("%d\n",d);
d=sizeof('1');
printf("%d\n",d);
}
As the variable a is integer, it gives 4 bytes. The datatype
int is of 4 bytes in size. The signed integral value -100 occupies, it gives 4
bytes. Generally, we consider the real data as floating. But, the gcc compiler
considers every real data as double by default. Hence sizeof(1.0) gives 8
bytes. In the last statement, ‘1’ is considered as a character. Though it is
considered as character, it is stored in the memory in the form of equivalent
ASCII, which is nothing but an integer. Hence, it gives 4 bytes.
Now, consider the following program with strings.
#include<stdio.h>
main()
{
int a;
a=sizeof("A");
printf("%d\n",a);
a=sizeof("gcchub");
printf("%d\n",a);
a=sizeof("123.45");
printf("%d\n",a);
}
When the data to the sizeof operator is given in double
quotations then every character is considered as one byte; at the same time, the
string is appended with the NULL character – ‘\0’, which also needs one byte of
memory. Hence, “A” gives 2 bytes, “gcchub” gives 7 bytes and “123.45” gives 6
bytes.
Finally, execute the following program to get some more
details about sizeof operator.
#include<stdio.h>
main()
{
int a=20,b=100,c=50;
printf("%d\n",sizeof(a)>a);
printf("%d\n",sizeof(a)>a);
printf("%d\n",sizeof(c++));
printf("%d\n",c);
}
The result given by sizeof operator is of unsigned int
datatype. Hence, both the comparisons sizeof(a)>a and sizeof(b)>b produce
0 as the output, as a and b are integers. In the next statement, there is sizeof(c++)
and then we have printed the value of c. For our surprise, c gives the output
as 50 though c++ mentioned. This is because sizeof is an operator but not a
function. Hence, c++ operation cannot be performed with sizeof operator.
Ternary operator:
This is the short form of if-else statement. This operator consists
of three operands and hence the name ternary operator. The syntax of ternary operator
is given below.
(condition)?(operand1):(operand2);
In this, if the condition is true, then operand1 is executed
and operand2 is executed otherwise.
Increment/decrement operators:
These operators are used to increment/decrement the given
variable by 1.
If the increment operator is placed “post” to the operand,
then it is called post increment operator; if placed before is called pre-increment
operator.
If the decrement operator is placed “post” to the operand,
then it is called post decrement operator; if placed before is called pre-decrement
operator.
Checkout the following example to differentiate pre/post
increment/decrement operators.
#include<stdio.h>
main()
{
int v=1,r;
r=++v;
printf("r:%d\tv:%d\n",r,v);
r=v++;
printf("r:%d\tv:%d\n",r,v);
r=--v;
printf("r:%d\tv:%d\n",r,v);
r=v--;
printf("r:%d\tv:%d\n",r,v);
}
In r=++v, v is first incremented by 1 (pre-increment) and
then the value is assigned to x. In r=v++, the current value of v is assigned
to x and the value of v is incremented by 1 (post increment). The same can be
extrapolated to decrement operator. To be still more precise about pre/post
increment/decrement operators, checkout the following program and give a try to
predict the output.
#include<stdio.h>
main()
{
int a=1,b=2,c=3,r;
r=a++ + ++b + ++c;
printf("a:%d\tb:%d\tc:%d\tr:%d\n",a,b,c,r);
c=r++ + a-- + b--;
printf("a:%d\tb:%d\tc:%d\tr:%d\n",a,b,c,r);
b=c-- + a ++ + --r;
printf("a:%d\tb:%d\tc:%d\tr:%d\n",a,b,c,r);
}
In the statement r=a++ + ++b + ++c, initially, a=1, b=2 and c=3. Here, a is post increment, b and
c are pre-increment. So, r is computed as r=1+3+4 i.e., 8. After calculating the
sum, a is incremented by 1 and then, the result is assigned to r. After the
execution of this statement, the status is a=2, b=3, c=4 and r=8.
In the statement c=r++ + a-- + b--,
the current values are considered for operation. So, c is computed as c=8+2+3. After
computing the sum, r is incremented and a, and b are decremented. After the execution
of this statement, the status is a=1, b=2, c=13 and r=9.
The statement b=c-- + a++ + --r is computed as b=13+1+8. After
the execution of this statement, c is decremented and a is incremented. The
status is a=2, b=22, c=12 and r=8.
0 comments:
Post a Comment