Vous êtes sur la page 1sur 28

Expressions is the most fundamental element of C language.

They are made up of two


atomic elements data and operator. C support variety of data types and large number
of operators. In simplest terms expression is a statement made up of data and
operators operating upon that data which is evaluated by compiler. Expression by
definition is any valid combination of operators, constants, functions and variables.
Expression in C language are very developed and sophisticated allowing you to to
complete the programming with uttermost ease and flexibility.

Contents -

1. Fundamental Data Types


2. Type Modifiers
3. Identifiers
4. Concept of Variables
5. Local Varaibles
6. Global Variables
7. Parameter Variables
8. C Scopes
9. Type Qualifiers
10. Storage Class Specifiers
11. Intializing Variables
12. Constants
13. Operators Overview
14. Assignment Operator ( = , += , -=, *=, /= )
15. Arithemetic Operator ( - , + , * , / , % )
16. Increment and Decrement Operator ( ++ , -- )
17. Relational and Logical Operator ( > , >= , < , <=, == , != , && , || , ! )
18. Bitwise Operator ( & , | , ^ , ~ , >> , << )
19. Question Mark Operator (?)
20. Star and Amprecent Operator ( * , & )
21. Compile Time Operator ( sizeof )
22. Comma Operator (,)
23. Dot and Arrow Operator( . , -> )
24. Square Brackets and Parenthisis Operator ( () , [] )
25. Operator Precedence
26. Expressions Evaluation
27. Type Conversion
28. Type Casting
29. Expression Formatting

1. Fundamental Data Type

8 Basic Data type defined by C are Character, Integer, Floating Point, Double
Floating Point, Valueless, Booledan, Complex &Imaginary. First 5 of these are
present in C89 while last three were added by new vesion of C99.Let discuss each of
them in brief -

1. Character - Implemented by char keyword. They are used to store ASCII character
and are always 1 byte long.
2. Integer - Implemented by int keyword. They are used to store integer value and are
always 4 byte long.

3. Floating Point - Implemented by float keyword. They are used to store decimal
values and are always 1 byte long.

4. Double Floating Point - Implemented by double keyword. They are also used to
store decimal values but with higher precision and are always 8 byte long.

5. Valueless - Implemented by void keyword. They are used to explicitly define


function returning no value or generic pointer. No variable of this type can be created.

6. Boolean - Implemented by _Bool keyword. They are used to store Boolean values
ie. True or False and are always 1 byte long.

7. Complex - Implemented by _Complex keyword. They are used to store complex


numbers and are operating system implemented.

8. Imaginary - Implemented by _Imaginary keyword. They are used to store


imaginary number and are operating system implemented .

One important point worth mentioing here is that C only stipulates the minimum
range of the data type and its size may vary according to system implementation. The
range may increase but will never get below the standard value. Also if you want your
program to be portable to maximum systems make use of compile type operator
sizeof in your program and allocate memmory dynamically instead of using default
memmory allocation.

2. Type Modifier

Type Modifiers are special keywords which can be applied to a data type to change
their meaning to more precisely fit the special needs they need to attain. There are 4
type modifiers define in C - signed,unsigned,long,short.Below we discuss each of
them one at a time.

signed - Can be applied to int and char. It changes the way the compiler interpret the
variable. 1st data bit is assumed to be a sign bit. Integer is signed by default but
character is unsigned. This modifier reduce the range to half of the maximum but
allows to implement some algorithms efficiently.

unsigned - Can be applied to int and char. It changes the way the compiler interpret
the variable. 1st data bit is assumed to be a data containg bit. Integer is signed by
default but character is unsigned. This modifier increase the range to maximum
(double of default) but cannot stored negative values.

short - Can be applied to int only. It enhances the portability of your program. Size of
int is 16 bits (2 b ytes) minimum but on some system it may become 32 and even 64
reducing portability of your program. To make sure you int is always 16 bits it is
recommended you use this modifier.
long - Can be applied to int and double. It enhances the portability of your program.
Size of int is 16 bits (2 b ytes) minimum but on some system it may become 32 and
even 64 reducing portability of your program. To make sure you int is always 32 bits
it is recommended you use this modifier. Also when applied to double it increase the
size from 64 bits to 128 bits, it doesnot increase the range but increase the digits of
precision. It is biggest size default data type though there is a experimental and
unstable data type in C99 long long double on 256 bytes but due to its implementation
limits it is highly recommend you dont use it. Long double is sufficient for even high
precision scientific values to large extent (unless you are calculation stars in the
universe).

It is important to note that modifier cannt be applied to void or float. Also you are not
permited to declare a void data type except generic pointers (which are internally int).

Also in case of int two different type modifiers can be simultaneously applied to
further enhance the meaning.

Below is a list of data types with thier size and range -

char 8 Bits -127 to 127


unsigned char 8 Bits 0 to 255
signed char 8 Bits -127 to 127Bits
int 16 or 32 Bits Operating system based
unsigned int 16 or 32Bits Operating system based
signed int 16 or 32 Bits Operating system based
short int 16 Bits -32767 to 32767
unsigned short int 16 Bits 0 to 65535
signed short int 16 Bits -32767 to 32767
long int 32 Bits -2147483647 to 2147483647
signed long int 32 Bits -2147483647 to 2147483647
unsigned long int 32 Bits 0 to 4294967295
float 32 Bits 1E -37 to 1E +37 Bits with six digits of precision
double 64 Bits 1E -37 to 1E +37 Bits with 12 digits of precision
long double 128 Bits 1E -37 to 1E +37 Bits with six digits of precision

One more point worth mentioning is default to int rule exisitng in C. Its obsolete now
but some compilers do provide them to give backward comaptibility but its highly
recomended you dont use them in any of your program. For curosity and knowledge
sake it states that if a type modifier is written by itself then it will be assumed a
modifier to a type int. In other words it means that -

signed A is interpreted as signed int A by Compiler.


unsigned A is interpreted as unsigned int A by Compiler.
short A is interpreted as short int A by Compiler.
long A is interpreted as long int A by Compiler.

Once again though int is implied it is a common practice to mention them anyway for
sake of compatability.
3. Indentifier

Name of any user defined item item in c is called identifier such as functions, labels
and variables.

Identifiers are of two types internal and external. Internal identifiers are one which
have internal linkage meaning that they are known only internally in file such as local
variables and static global variables. External identifiers are one which have external
linkage meaning that they are known only outside their file such as function names
and global variables.

In C identifiers can have any number of character but not all of them are
significant.Significant characters are the character used to identify the identifier. For
an identifier to be unique it must have name different by atleast 1 character from all
other identifiers in the same scope. C89 specifies that atlest 6 characters of an external
specifier and 31 characters of an external identifier be significant. C99 further relaxes
this constraint stating that atlest 31 characters of external identifier and 63 characters
of internal identifier must be significant. Though generally compilers make sure that a
larger number of characters be significant but minimum number is always instated.

Names of identifier has to follow some rules -

1. They may contain only alphabets, digits and underscore, example Hi!!!, I.Love.You
is incorrect.

2. They must start with an alphabet or underscore, example 1_Counter is an inavlid


identfier.

3. They cannot be same as keywords because these are the words reserved from usage
by C.

One important point is that your identifier can have same name as the function in the
library but this may induce some serious error, especially if you include the header
file with similar name function. In this case whenerever you refrence the function it
will refer to your code function even when you desire to use the library function,
simplest way avoid this bug to give your functions a different name.

It should be noted that c is type sensitive language that its identifiers are case
dependent eg- C_ROCKS, C_rocks and c_rocks are all different identifiers in C.

Also it is recommended that you use a standard notation while naming the identifiers.
Famous ones are hungarian notation and camel case notation. These standards while
correctly applied can lead to many benefits such enhanced portability and
maintainability. These factor gain importance as the size of the project increases.

4. Variable Overview
Variable referes to a location in memmory that can be used to a value that can be
dynamically or statically modified by your program.

All variables must be declared before there are use, basic syntax is

<Type Modifier> <Type> <Identifier>; Example - unsigned int a ;

Above type modifier is optional.

Identifier used as variable name should comply with the rules stated above.

Varibles can be of three types -

1. Local

2. Global

3. Parameter

Each type has its own scope, limitation and function as discussed below

5. Local Variables

Variables that are declared withn a function are local variable. They are also known as
automatic variables but the term is obsolete.

Earlier local variables were declare using keyword auto butnow this keyword is
implicitly applied as a result the use of this keyword in modern source code is
virtually non exsistent but do keep it in mind if you encounter it in earlier codees.

Local variables have property that they can be accesed only in the code they are
defined in. Code block starts with the { and ends with } ie. within a pair of curly
brackets the code block exist.

Life span of global variables is for the period in which code block is executing. They
get created when code block is entered and get destroyed when code block is left.
They are stored on stack of your compiler which is a dynamic data storage which is
the reason that local variables cannot retain their value. This property can be modified
by static keyowrd, this is discussed below.

It is a rule in C that you must declare a local variable before using it. Also in C89 its a
rule that all declaration of variables must be made before any executional statment of
the code block bbut in C99 (like C++) it can be declared any where prior to its first
refrence.

Note that two variables with same identifier (name) cannot be stored in same code
block and would reslut an error by compiler, but same name local variables can exist
in different code blocks and even aggregated code blocks (one inside another).
When the same name variables are used in different functions they bear no relation
and doesnt know nor depend on other's existence.

When the same name variables are used in an agrregated code block, ie. one variable
in outside code block and one in inside code block the inner one mask the outer one.
After ineer code block ends the outer variable again comes into existence.

Following C Source code will help you grasp the detail of the topic -

#include <stdio.h>

void f1 (){
int x = 10;
printf ("%d",x);// Outputs 10
}void f2 ()
{
int x =20;
printf ("%d",x); //Outputs 20
} int main (){
int x = 30;
{
int x = 40;
f1 ();
f2 ();
printf ("%d",x); //Outputs 40
}
printf ("%d",x); //Outputs 30
return 0;
}

6. Global Variable

Unlike local variable global variable are known throughout the program. They are
declared outside all function and conventionally just after the include statements.

They should be use carefully and only when there is a defetive gain in performance or
efficiency or they provide ease in programming. Most of the time they are used to stoe
shared data but beautifully crafted programs also used them to store control
information as control flags.

The major problem with global variables is that they lead to bugs which are very
difficult to debugg and very easy to occur because the value of a global value can be
easily modified by an undesirable side effect of your code. Also storage of global
variable is on a fixed memory region which is non volatile for program life period. As
a result a global variable always tend to bloack memory not only for a particular
function execution but for entire program execution time as a result large number of
global variables may overrun the memory allocated to your program leading to
serious trouble. So global variables must be used when there is an absolute must.
A special situatuion occurs when global variable and local variable has same name. In
this case the local variable mask the global variable and all refrences are made to it
within its scope.

C Source Code below will clarify the situation -

#include <stdio.h>

void f1 ()
{
int x = 10; //Outputs 10
printf ("%d",x);
}void f2 ()
{
x =20;
printf ("%d",x); //Outputs 20
} int main ()
{
int x = 30;
f1 ();
f2 ();
printf ("%d",x); //Outputs 30
return 0;
}

7. Parameter Variable

Parameter variables are used for passing values between functions. Value maybe
control information or data.

They are very similar to local variables in a sense that they are dynamic and have life
span of that of local variable. Even though they recieve paramet value they can act
like a local variable and reassign values to the parameter variable.

Their main job is to get automatically intialize based upon the data passed.

C Source Code Illustrating formal parameters -

#include <stdio.h>

void f1 (int x)
{

printf ("%d",x);//Outputs x
}int main ()
{
int x = 30;
f1 (x*5);//Outputs 150
f2 (x+10);//Outputs 40
printf ("%d",x); //Outputs 30
return 0;
}

8. C Scopes

A visibilty of an identifier is determined by its scope. C defines 5 scopes which have a


very fine yet important differences.

1. Global/Universal Scope - This scope is given to identifiers which are known


through the project. Normal global variables and function names come under this
scope.

2. File Scope - This scope is given to identifiers which are known only in the file they
are declared. Staic global variables come under this scope.

3. Block Scope - This scope is given to identifiers which are known only in the code
block they are declared. Local variables come under this scope.

4. Function Prototype Scope - This scope is given to identifiers which are known
through a function to which they are passed as parameter. Parameter variables come
under this scope.

5. Function Scope - This scope is given to identifiers which are known through
thefunction. Labels identifier use to target goto statement come under this category.

Also there are three type of linkage defined in C which is very similar to scope -

1. External Linkage - Same as Universal Scope and is applied to global variables and
function name.

2. Internal Linakge - Same as File scope and is applied to static global variables.

3.No Linkage - Combination of Block, Function and Function Prototype Scope and is
applicable to local variables, parameters and labels.

These are rarely used terms which are used when the task of making fine distinction
in identifier visibility is needed.

9. Type Qualifier
Type qualifiers in c are used to specify and contro the acess and modification of a
variable. There are 3 type Qualifiers in C - const, volatile and restrict. They must
precede the type name that they qualify. Each of type qualifier is discussed below in
detail.

1. const - It is a very usefull keyword available to a cprogrammer but its usage is not
that prevelant in comparison to potential and benefits its provides. const keyword
provides many utility applicable to situtation they are applied.

When its applied to a varaible then value of variable cannot be modified by your
program. They can be used as a constant. Also they can be intialized but after
intialization there value is not changable by any software means.

When its applied to a pointer then the object its pointing to cannot be modified by the
program. Though the value its pointing can be changed by other means but not by this
pointers.

Situations you should use this keywords are special. This keywords can prevent bugs
in your program by making sure that an essential constant value doesnot get modified
as a side effect leading to incorrect result. This keyowrd is also applicable in
situations in which you pass falue to a function by mean of pointers or in other terms
call by refrence. In this case the function has the ability to modify input data in the
original source. Now if you are pretty sure that you dont want this function to change
your intial values you can pass the pointer as a constant pointer making sure that
value pointed by that pointer cannot be modified.

For optimization purposes some compilers may also place the value in ROM so they
are absolutely unmodifiable.

One elegnat example of use of const keyword is seen in standard library functions
provided with C. All the parameter this function does not want to modify are declared
as const. You should use the same approach as it will save you a lot of headache when
the failure of your programs occur because of preventable bugs.

One very important point about const is that its value can be modified by hardware
means (sometime desired, most of time undesired). This can also lead to bugs but its a
very rare situatuion when some harware fault occurs such as memmory overflow etc.
But using const keywords prevents modification by any software mean.

Its also well known fact that const keywords enhanced security of you software and
also pose a mjor difficulty in reverse engineering processes.

2. volatile - This one of the rarest used C-Keyword and find special used in hardware
dependent programs such as drivers or system clock based code. Its specifies that the
variable can change without any implicit specification. In other words the variable
value can change even if doesnot assign a new value by program.
This is neccesary because in order to optimizse the code the compilers change the
order of evaluation or may even not check the new value of variable if they observe
that the variable does not occur on left in any assignment statement. This feature can
surely sabotage your hardware dependent code in which values changes automatically
also at very high frequency. Using volatile keyowrd prevents this optimization and
make sure complier check the value of the variable every time it is used.

Many programmers beleive that const and volatile are opposite of each other but in
relaity they point to entirely diffrenet aspects. You can even use them on same
variable, in this case it will specify the variable value changes dynamically but can
only be accesed by your code as constant.

3. restrict - This is one of the newest features added to C. It is only available in C99.

Its only applicable to pointers.

It states that a restrict pointer is the only mean by which the data pointed to that object
can be accesed. Data accesed from any other pointer is possible if and only if its based
on the first one.

The major functionality it provides is that it enables the compilers to produce highly
optimize code.

To programmers it provides a tool by which they can make sure that if a pointers is
restrict it provides the sole access method to the data it is pointing.

Also one important deduction that can be made out that if two pointers are restrict
they are pointing to entirely different data ie. the data they are pointing is non
overlapping.

Like const , restrict keyword is also extensively used by the library function and users
are recommended to use them to improve efficiency of their code.

The C source code below shows an simple application of type qualifiers -

#include <stdio.h>

int main ()
{
const int x = 30;
cont volatile int * port = (const volatile int *) 0X1E;
int *restrict point = &x;
printf ("%d %d %d",x, *point, *port); //Outputs 30, 30, 30
return 0;
}

10. Storage Class Specifier

Storage class specifier when applied to variable tells the compiler how to store that
variable. Storage class specifier always precede the varaible declaration. There are 4
storage class specifier defined in C. These are extern, static, register & typedef and
are discussed in detail below.

1.extern - There are 3 general use of extern.

First , extern was once used before functions name to identicate the function has
global scope but since now all the functions are automatically put into global scope
this use is now virtually no existent.

Second use of extern is declaring that a global varible used in the file is from an
external file. Though global variables have global scope they may be masked by
variable of same identifier. Hence to make sure the global one is used we use external
specifier. Also generally such declarations are made into header files and are specially
usefull in programs splitted into many source files.

Third use of extern is most commonly used and enables a programmer to use a
variable without defining by marking its declaration as extern. Some users may be
confused by declaration and description so a brief description is appropriate. C
defines that a varaible can have any number of declaration but only 1 definition.
Declaration is the statement which tells the compiler what type of datat type that
varible is such as statement int i; this statement only declares the code but doesnot
define it. On other hand when you assign any value to a variable it get defined. In
other words when first memmory is allocated the varaible is getting declared. If you
intialize the variable while defining it you are declaring as well as defining in one
statement. Extern just specifies that declaration of the variable is present but not in the
same scope so compiler searches for it high and low for resolving this refrence.

The order in which refrence search is made is important.First the seacrch is made in
bloack scope then in function scope then in file scope and in last universal scope.
Compiler assumes that any definition which match the declaration first is the variable
being refered to. In other words if variable definition is found in functions scope then
C compiler doesnot search the file and universal scope. If no correct refrence is found
then linker flanks an error message.

C Source Code showing use of extern is -

#include <stdio.h>int main (void) { extern int a; printf ("%d" , a);


// Displays 10; return 0;} int a = 10;
2. static - This is a very high utility keyword and is frequently used in programming.
The are applicable to user defined variables (except parameter) and have an entirely
diffrenet effect when applied depending upon the scope of variable.

When applied to global variables its scope is limited to file only ie. other files
included in the program has no clue of its existence. They provide a very powertool of
hiding data and creating stand alone function because of which they are also used in
library functions. The global variables of your stand alone function will be completely
usefull in that program but are shielded from external effects when combined in a big
program. The value of these variables can be modified only by the function in that
source file and not outside it preventing bugs, mishandling and probably unauthorize
access and program tempering.

When applied to local variables the variable is stored in global variable memmory
space and not on stack. Even though the varaible has functions scope it does not get
destroyed like local variable when function returns, instead it retains it value on next
call. Static local varaibles are intialised only once on the first function call. They
provide high functionality in certain algorithms. If they were not available global
variables have to be used for them but this makes program ureliable because it is
depending upon something thats outside it. In Software analysis term this increases
programs coupling (dependence on others) and decreases there cohesion (Capability
of work alone). It is just opposite of what we desire. Ideal module/subroutine is the
one which has minimum coupling and maximum cohesion.

C Source Code Example below shows functionality of static keyowrd -

#include <stdio.h>static int callfunction; void function (void) {static int a = 0;a++;
printf ("Function have been called %d time",a); }int main (){ callfunction = 10;for
(int i = 0; i<callfunction;i++) { function (); } return 0;}

3. register - This is a highly oeprating system and compiler dependent keyword. It is


so dependent that it is allowed to a C compiler to even ignore them as if they never
exsted and even then they will be complying with standards of C. Though on other c
also states that this keyoword should be given prime importance where it is
applicable.

A register variable is stored in CPU register instead of RAM and its a well known fact
that there is nothing that provides faster access than CPU register. This register is very
dynamic and also provided very very very limited space. Register are used by CPU
for addressing RAM memmory but a register declared variable is stored in CPU
register itself hence they prrovide very fast access to read and write.

Using a register keyword can make your program faster by many folds if properly
used. CPU register are so limited that only 1-2 live variables can placed on it that also
of non aggregate type (basic ones). So make sure you make only that variable register
which have an drastic impact on the program, loop variables make excellent choice.
Use register carefully keeping its limitation in mind at all times.
Also you dont have to worry about declaring too many variables register as compiler
manage them for you but it doesnot decide on basis of impact on program, its your job
and you have to tell compiler about them.

Also making a variable, a register variable is dependent upon many other constraints
such as size of CPU registers, number of free registers with CPU, access to CPU
register and much more so they are innately dependent on hardware and operating
enviroment.

Following C Source code illustrates the use of registers -

#include <stdio.h>

int main (void)


{
register int a;
for (a = 0; a < 10;a++)
{
printf ("%d", a); // Prints numbers 0 to 9

}
return 0;
}

4. typedef is a very contoversial storage class specifier because in actual it doesnt


allocate storage neither defines or modify type of storage when applied to variable
still it is defined in standard c under category of storage class specifier so we will
discuss it here.

typedef keyword provides syntactic convienence. Using typedef we can rename a


particular base data type. This doesnot create a new data type but only rename the
base data type.

The name is not replacement but is addition and can be used again in a typedef
expression to once agian create a new data type name of the original data type.

Typedef offers two advantages -

1. It makes your code portable since you are using your own name for the code
generated by compiler for a particular enviorment, when you move to a new
enviorment all you have to do is to modify the typedef statements according to the
new enviorment and compile agian.

2. It creates a self documenting code, since new data names implies a closer meaning
to reader who is reading than a basic data type name. This makes code easier to
understand.
Read the C Source Code below to improve your understanding.

#include <stdio.h>

int main (void)


{
typedef int age;
typedef age weight;

int a;
age b;
weight c;
return 0;
}// Here all three variables a, b and c are of type int.

11. Intializing Variables

Intializing a variable is a process of declaring as well as defininf it. It is when a real


memmory is allocated to it.

Basic intialization technique is using assignment operator, eg - int a = 0;

Multiple intialization technique eg - int a = 0, b = 10, c, d = 20;

Global variables and static local variables are intialized only once.

Local variables are intialized each time they are created or thier code block is entered.

Also unitialized static and local global variable are set to zero before thier prior use.

Uninitalize local variable contains undefined value (Random) before thier prior use.

Using an unitialized variable specially the local variables and pointers can lead to
intense bugs which are even capable of entire system crash. To prevent this some
compilers will indicate error but almost all of them will flank a warning to make sure
it is not by a mistake (Some special cases such destroying a enemy computer this may
find some good use but they are still unrelaible so study virus and trojan section, just
kidding).

12. Constants

Constants refer to fixed values which your program cannot modify. They are also
known as literals. You also make an varaible a constant by using const keyword as
describe above. There are different types of constants including the a type from every
basic data type. They can be broadly classified as data type constatns, base constants,
string constants and back slash constants (escape sequences). We discuss each
category below.
1. Basic Data Type Constants - All basic type have an constant associated with it. If
not explicitly specified the c compiler allocates the minimum size data type to it
capable of storing it but compiler also make sure it does not cross any type
boundaries. One exception to previous statment is that the floating point value by
default is double and not float even tough double has larger size. Below is all types of
basic data type constants defined in C.

character - 'c'

multibyte character - 'cc'

wide character - L'c' or l'c'

int - 101

signed int - 101 (same as int as int is signed by default)

long int - 101L or 101l

unsigned int - 101u or 101U

float - 101.01f or 101.01F

double 101.01

long double 101.01L or 101.01l

The character following the constants is called type suffix in c and is case
independent.

2. Base Constants - As you probably knowing there are different number systems
other than decimal, most improtant one among them is Hexadecimal and Octal
Constants. Hexadecimal is a number system 0 - 16 while octal is number system 0-8.
It is some time easier to use these special number systems than decimal specially
while doing hardware programming through in which port values are Hexadecimal.
Also they are usefull when you use them constatnly for some calculation, in this case
you dont need to particulary feed equvalent decimal value to C because C provides
automatic to and fro base conversion calculation. This is where base constant comes
in telling compiler which base the value in the constant bleongs to a C then store its
equvalent value in any internal way it prefers.Diffrent base constant are -

Decimal - 420

Octal - 0420 (starts with explicitly specified 0)

Hexadecimal - 0x420 (starts with explicitly specified 0x)


3. String Constant - String is a special type of constant which contains on more
particluar sequence of characters. The characters are represented between double
qoutes. Eg - "Hi".

4. Backslash Character constant or Esacpe Sequences - These are special characters


defined in C to be used as character constant or in strings. They are used to write
special characters which can not be written by keyboard in C. Various escape squence
defined in C are -

\a alert or beep

\b Backspace

\f Formfeed

\r Carraige return

\n New Line

\t Horizontal Tab

\v Vertical Tab

\" Double Quotes

\C Octal Constant (where C is an Ocatal Constant)

\xC Hexadecimal Constant (where C is an Hexadecimal Constant)

\' Single Quote

// Backslash

\? Question mark

13. Operator Overview

Operators is a symbol used to relate two operands. When one or more such relations
are combined we get an expression. C have highly developed and sophisticated set of
operators providing the ability to programmer to do anything with maximum
flexibility. Operators can be broadly classified into arithemtic, relational, logical,
bitwise and miscellaneous. All the operators defined in c are discuss in subsequent
topic in small related groups.

Operator can be of 3 types -


1. Unary opertor - accpets 1 operand. Eg - ++, -- , -

2. Binaryopertor - accpets 2 operand. Eg - +, - ,*, / ,

3. Ternary opertor - accpets 3 operand. Eg - ?

14. Assignment Operator

Assignment operator is used to assign values obtained from a expression to another


variable. General form is

lvalue = rvalue;

here lvalue refers to left value and should be a modfiable variable.

rvalue refers to right value and should be a valid epression statement.

If automatic conversion is not possible in assignment type casting should be


employed.

You can also use multiple assignements -

Eg- x=y=z= 0; this statement assign value zero to three varibles simultaneously.

There are also shorthand assignment operators/Compound Opertors which performs


simultaneous task of assingment and arithemetic. These are += , -= , *= , /= , %=.
These operands are always used whereever possible over thier expanded equivalent in
a professionaly edited code.

For eg -

X += Y is equivalent to X = X+Y

X -= Y is equivalent to X = X-Y

X *= Y is equivalent to X = X*Y

X /= Y is equivalent to X = X/Y

X %= Y is equivalent to X = X%Y

15. Arithmetic Operator

Arithemetic operators do most of the basic arithemetic calculations. Artihemtic


operators define in C are -

+ does addition Eg - 4 + 3 = 7
- does subtraction Eg - 4 - 3 = 1

* does multiplication Eg - 4 * 3 = 12

/ does division Eg - 4 / 3 = 1.333

% does modulus Eg - 4 % 3 = 1

- unary minus Eg - -(4) = -4

The result produce by these arithemetic operator is same as largest variable input ie.
4/3 = 1 , 4.0/3 = 1.33 , 4/3.0 = 1.33 & 4.0/3.0 is 1.33 . 4/3 is 1 because all constants in
expression are int while in all other atleast one or more operand operated by opertor is
float

16. Increment and Decrement Operator

These are special arithemetic operators which are used to increase or lower the
variable value by unity (1). Symbols for them are ++ (increment) and -- (decrement).

They should be used where possible because the code produce this way is more
optimized specialy in case of linearly incremented code.

x+1 is equivalent to x++ or x--

x-1 is equivalent to x-- or x--

Though ++x and x++ and similarly x-- and --x employs same equivalent circuit they
when used with assignment operator result into extremely diffrent result. The first
form is called prefix and other one is called postfix form.The main difference is when
assignment occurs with respect to increment or decrement.

Consider to variable x & y. Y having value 10 then in case

x = y++; x contains value 10 because increment is performed after assignemnt.

x =y++; x contains value 10 because increment is performed before assignemnt.

It should be noted that y is 11 in both cases.

17. Relational and Logical Operator

Relational operators used to calculate realtionship between variables while logical


operators calculate the logic in these relationship. Since most of the times they are
used together we will discuss them together.

They work on boolean data and produces boolean data. In C any 0 value is considered
flase and any non-zero value (generally 1) is consider to be true. C99 also defines a
data type _Bool which can store only two values true (1) or false (0).
Relational operators return 0 or 1 depending upon the validity of the condition they
are checking. Various realtional operators defined in C are -

> Greater than

>= Greater than or equal to

< Less than

<= Less than or equal to

== equal to

!= not equal to

Logical operators return 0 and 1 by testing various logical relationship among


themselves using logic properties. Various logic symbol in C are -

&& Logical AND

|| Logical OR

! Logical NOT

x y x&&y x||y !x0 0 0 0 1


0 1 0 1 1
1 0 1 1 0
1 1 0 1 0 All other logic operator such as XOR , NOR, NAND can be
implemented using combination of these operators.

Paranthesis as usual can be used to change their precedence.

Eg- ((3>4) && (2==1)) || ((4>3) && ~3 ) = ((0) && (0)) || (1 && 0) = 0

18. Bitwise Operator

C was intially designed to replace the assembly language and used for system
programming such as driver designing and port maintainance. These devices innately
contains the job of working with smallest element of storag bits and bytes. Bitwise
operators defined in C provides this capability in which you can play with bits and
bytes.

Relational operators are applicable to only char and int types. Various types of
relational operator are -
& And, Used to logically and all the bits in the two operands and return the resultant
output.

| Or, , Used to logically or all the bits in the two operands and return the resultant
output.

^ XOR , Used to logically XOR all the bits in the two operands and return the
resultant output.

~ Complement , Used to logically complement all the bits in a operand. Also using
complement twice original result is produce.

<<n Shift lefy, Used to logically shift all the bits in the operands n postions left and
introduce zero from right and return the resultant output. The shift left bit is lost and
cannot be returned.

>>n Shift right, Used to logically shift the bits in the operands n postion right and
introduce zero from left and return the resultant output. The shift right bit is lost and
cannot be returned.

Consider an example in which we work on char variable A (8bits) with value 7 in


binary equivalent to 00000111 and B with value 13 with binary equivalent
00001101Then if

C= A & B then C = 00000101 => 5

C= A | B then C = 00001111 => 15

C= A ^ B then C = 00001010 =>10

C= ~A then C = 11111010 => 250

C= A>>1 then C = 00000010 => 2

C= A>>1 then C = 00001010 => 6

Truth Table For XOR -

x y x^y
0 0 0
0 1 1
1 0 1
1 1 0

One important point to note about bit shifting is that if A = B>>n bits then its is
equivalent to B/n and if A = B<<n bits then its is equivalent to B*n as long as the bit
lost in the shifting procdure is 0. If bit loss is 1 then there is a loss of data and this
realtion does not hold true.

19. Question Mark Operator

Question Mark as name sugests is symbolize by ?. This is the only ternary operators
in C. In other words this is the only operand which takes in three simulatenous inputs.

This operators major use is to replace an smal if then else statement.

Its general form is V = Exp1? Exp2 : Exp 3.

It means that Exp 1 is evaluated and if its true value of variable V is one obtained by
solving EXP2 & if its false value of variable V is one obtained by solving EXP3.

Following C source code displays the use of Question mark operator-

#include <stdio.h>

int main (void)


{
int x;
x = 1;
x = x>0 ? x : -x; // ternary operator used to find modulous
printf ("%d", x);
return 0;
}

20. Star and Ampercent Operator

Star operator is represented by * and Ampercent operator is represented by &. They


are used in context with pointers which is the greatest all features in c. They are
discussd in further tutorials.

Pointer is basically and address or memmory location of a variable.

* is used to reterive value from a location assuming that variable it is applied to store
the memmory location to that value. It is also used in declaring pointers.

& is used to reterive adress of variable, it is used to retrieve the memmory location of
that variable and this address is used as a feed to the pointers.

Though pointers are discussed in very minute details in further sections what follows
is a C source code showing pointers in action -

#include <stdio.h>
int main (void)
{
int source, target;
int *pointer;
source = 100;
pointer = &source;
target = *pointer
printf ("%d", target);
return 0;
}

21. Compile Time Operator

C only provides one compile time operator known as sizeof.

If sizeof is used efficeintly the object code produced by the compiler is precisely
targeted to the enviorment and also your source code is extensively portable.

It is a property of sizeof that its value is determined at compile time and is dependent
upon the hardware and operating system.

sizeof returns the size of the object passed to it as parameter in parenthesis. The value
of size it return is a of type size_t which is some type of unsigned integer capable to
returning maximum possible size.

As you know integer can be 16 or 32 or even 64 bit which can make your code very
unportable a solution to the problem is to allocate memmory to the int variable
dynamically depending upon the size of int variable in the enviorment usinf sizeof.

#include <stdio.h>
#include <alloc.h>

int main (void)


{
int* x;
x = (int *) malloc (sizeof (int)); // Use of sizeof to dynamically allocate memmory
*x = 1;
printf ("%d", *x);
return 0;
}

22. Comma Operator

Comma opertor as you cn guess is represted by ,

Comma operator is a operator with lowest precedence.


It is used to combine together several expression in one expression.

In comma operator all the expression on left evaluates to null and the rightmost
expression becomes the value of the entire comma seprated expression.

The use of comma operator may be clear from following C source code -

#include <stdio.h>

int main (void)


{
int x,y;
x = (y=4,y+3); // Used of comma operator to string two expressions.
printf ("%d %d", x,y);// Displays 7 and 4
return 0;
}

23. Dot and Arrow Operator

Dot operator is represented by . and arrow operator is represented by ->.

Both of these operators are used with union and structures which are discussed in
detail in further sections. For brief knowledge Union & Structures are user defined
aggregated data types. In strucutre each internal element has its own unique structure
while in union they share

Dot operator is use to access or modify data from structure and union directly.

Arrow operator is use to access or modify data from structure and union using
pointers.

Following C Source Code show the use of dot and arrow operator -

#include <stdio.h>

struct data
{
int value1;
int value2;
}

int main (void)


{
data d1;
data* d2;
d1.value1 = 10;
d1.value2 = 20;
d2->value1 = 30;
d2->value2 = 40;
printf ("%d %d", d1.value1,d1.value2);
printf ("%d %d", d1->value1,d1->value2);
return 0;
}

24. Square Brackets and Parenthesis Operator

Square Bracket operator is represented by [ ] and Parenthesis operator is represented


by ( ).

Square brackets is used to index Arrays. Arrays are discussed in details in further
sections. In breif, arrays is collection of similar data types stored in sequential
memmory locations of which each element can be accesed through an index.

Following C Source Code show the use of Square Bracket and Parethesis operator -

#include <stdio.h>

int data [5]; // int array

int main (void)


{
int i, answer;
for (i = 0; i<5;i++)
{
data [i] = i; // Array indexing using square brackets with help of a loop
}
answer = ((data [0] + data [1]) * (data [2] - (data [3] % data [4]))) // Use of parethesis
to modify precedence
printf ("%d", answer); // Displays -1
return 0;
}

25. Operator Precedence

When compiler parse the code it does some operators calculation earlier than others if
order is different this may lead to a diffrent result to solve this problem compiler use a
precedence table to decide which operator has to be solved first. This order can
modified by parenthesis operator (( )) which has highest precedence. Higher
precedence operator will calculated before lower precedence operator. Operators on
same level can be solved either left to right or maybe reshuffled by compiler to
produce optimize ouput.

Precedence of operators are as follow -

Highest :
( ) [ ] -> .

! ~ ++ -- - (type cast) * sizeof &

%/*

-+

<< >>

<= < > =>

== !=

&

&&

||

= += -= *= /= %=

,(comma)

: Lowest

26. Expression Evaluation

In a expression order of evaluation is decided by user by using parenthesis.

All subexpression that have to be solved on same level can be freely rearrange by
compiler in any order to optimize code efficiency and some employ parsing them left
to right but if you want a portable code you cannot make this assumption always true.
This rearranging can also lead to some hard to find bugs which are caused by
undesirable rearrangement and execution order. So as programmer it is your job to
make sure that your code does not rely upon the execution subexpression. Situation
can be described by the code below -

#include <stdio.h>

int input = 10;

int f1 ()
{
input = input*5;
return input;

int f1 ()
{
input = input+ 10;
return input;

int main (void)


{
sum = f1 ()+ f2 (); // Unreliablity introduce due to rearrangement of sub expressions
by compiler.
//Any one of f1 () or f2 () can be executed first.
printf ("%d" , output); // Ambigious output (110,120)
}

27. Type Conversion

When variables and constatns of diffrent types are mixed in a single expression they
all converted to same type.

General rule follow by the compilers is that all variables and constants are promoted
to the largest type occuring in the expression this is called type promotion. Also result
is return in this largest variable type.

Largest variable types are listed in decreasing order. If any operand is of not the
largest type variable then next largest varible type is checked until the right one
occuring in realation is found and then all the trems in that expresssion is - long
double >> double >> float >> unsigned long int >> long int >>unsigned int >> int >>
short int >> char

Type conversion may some time lead to loss of data when a bigger size type casted
into smaller type the table shown below indicat possible cases for char.

Target Type Expression Type Possible Loss Of Data

char int(16) High Order 8 Bits


char int (32) High Order 24 Bits
char short int High Order 8 Bits
char long int High Order 24 Bits
char float High Order 24 Bits and preicision
char double High Order 56 Bits and precision
char long double High Order 120 Bits and precision
Similarly cases of all variables into other types can be calculated from their size

28. Type Casting

Type casting is an neccesary evil. C provides most of the automatic conversion


between various compatible types but there may arise cases in which you dont want to
use C's inbuilt type conversion or it is not capable of converting it. In this case you
use a very powerfull tool know as type casting.

In C type casting allows you to convert a varible, constant or data of any type from
any type. Casting leads to conversion atoccurs at binary level.

Its also a very dangerous things because when you do a unusal type casting you obtain
a value in a variable which was never built to handle and when you used this variable
there is on guessing what could happen. So be very very carefull while using type
casting.

The genral syntax for typing casting when you have to convert a type1 into type 2 is

type2 variable = (type2) type1 variable.

Code below illustrates a simple type conversion -


#include <stdio.h>

int main (void)


{
int a;
for (a = 0; a < 10;a++)
{
printf ("%f", (double) a/2); // Prints a float number even though variable is an int
}
return 0;
}

29. Expression Formatting

This very essential for a expression. You can create a unformatted expression code
readable by compiler without any error but same code when read by somebody may
literally throw him off and confuse it beyond limit.

You should use parenthesis to remove ambiguity from your expression.

Also spacing and tabiing should be added to expression to make it more readable.

Contray to general belie formatting does not have any beneficial or negative effect on
your code. But proper formatiing can surely prevent headaches to you and anybody
else trying to figure out the significance and meaning of the code. These formating are
completely ignored by compiler. Some IDE also provides tool to automatically format
the source code to a readble format. These tools are also available in stand alone form.

For eg - What is easy to read for a human even though both expressions are same

A = X/4-34*Y+2/2-7*9;

A= (X/4) - (34*Y) + (2/2) - (7/9);

As you are becoming a talented C Programmer reading these articles it is higly


recommended you make a habit of proper formatting of expression as well ascoding.

Vous aimerez peut-être aussi