Вы находитесь на странице: 1из 33

Introduction to Programming

Languages/Grammars
← Programming Language Paradigms · Parsing →

Jump to navigationJump to search


A programming language is described by the combination of its semantics and its syntax. The
semantics gives us the meaning of every construction that is possible in that programming language.
The syntax gives us its structure. There are many different ways to describe the semantics of a
programming language; however, after decades of study, there is mostly one technology to describe
its syntax. We call this formalism the context free grammars.
Notice that context-free grammars are not the only kind of grammar that computers can use to
recognize languages. In fact, there exist a whole family of formal grammars, which have been first
studied by Noam Chomsky, and today form what we usually call the Chomsky's hierarchy. Some
members of this hierarchy, such as the regular grammars are very simple, and recognize a relatively
small number of languages. Nevertheless, these grammars are still very useful. Regular grammars
are at the heart of a compiler's lexical analysis, for instance. Other types of grammars are very
powerful. As an example, the unrestricted grammarsare as computationally powerful as the Turing
Machines. Nevertheless, in this book we will focus on context-free grammars, because they are the
main tool that a compiler uses to convert a program into a format that it can easily process.
Grammars[edit]
A grammar lets us transform a program, which is normally represented as a linear sequence
of ASCII characters, into a syntax tree. Only programs that are syntactically valid can be transformed
in this way. This tree will be the main data-structure that a compiler or interpreter uses to process the
program. By traversing this tree the compiler can produce machine code, or can type check the
program, for instance. And by traversing this very tree the interpreter can simulate the execution of
the program.
The main notation used to represent grammars is the Backus-Naur Form, or BNF for short. This
notation, invented by John Backus and further improved by Peter Naur, was first used to describe
the syntax of the Algol programming language. A BNF grammar is defined by a four-elements tuple
represented by (T, N, P, S). The meaning of these elements is as follows:

 T is a set of tokens. Tokens form the vocabulary of the language and are the smallest units of
syntax. These elements are the symbols that programmers see when they are typing their code,
e.g., the while's, for's, +'s, ('s, etc.
 N is a set of nonterminals. Nonterminals are not part of the language per se. Rather, they help to
determine the structure of the derivation trees that can be derived from the grammar. Usually we
enclose these symbols in angle brackets, to distinguish them from the terminals.
 P is a set of productions rules. Each production is composed of a left-hand side, a separator and
a right-hand side, e.g., <non-terminal> := <expr1> ... <exprN>, where ':=' is the separator. For
convenience, productions with the same left-hand side can be abbreviated using the symbol '|'.
The pipe, in this case, is used to separate different alternatives.
 S is a start symbol. Any sequence of derivations that ultimately produces a grammatically valid
program starts from this special non-terminal.
As an example, below we have a very simple grammar, that recognizes arithmetic expressions. In
other words, any program in this simple language represents the product or the sum of names such
as 'a', 'b' and 'c'.
<exp> ::= <exp> "+" <exp>
<exp> ::= <exp> "*" <exp>
<exp> ::= "(" <exp> ")"
<exp> ::= "a"
<exp> ::= "b"
<exp> ::= "c"

This grammar could be also represented in a more convenient way using a sequence of bar
symbols, e.g.:

<exp> ::= <exp> "+" <exp> | <exp> "*" <exp> | "(" <exp> ")" | "a" | "b" | "c"

Common symbols[edit]
The American National Standards Institute (ANSI) set standards for flowcharts and their symbols in
the 1960s.[14] The International Organization for Standardization (ISO) adopted the ANSI symbols in
1970.[15] The current standard, ISO 5807, was revised in 1985.[16] Generally, flowcharts flow from top
to bottom and left to right.[17]

ANSI/ISO
Name Description
Shape

Shows the process's order of operation. A line coming


from one symbol and pointing at
Flowline (Arrowhead)[15]
another.[14] Arrowheads are added if the flow is not the
standard top-to-bottom, left-to right.[15]

Indicates the beginning and ending of a program or


sub-process. Represented as a stadium,[14] oval or
rounded (fillet) rectangle. They usually contain the
Terminal[14]
word "Start" or "End", or another phrase signaling the
start or end of a process, such as "submit inquiry" or
"receive product".

Represents a set of operations that changes value,


Process [15]
form, or location of data. Represented as
a rectangle.[15]
Shows a conditional operation that determines which
one of the two paths the program will take.[14] The
Decision[15]
operation is commonly a yes/no question or true/false
test. Represented as a diamond (rhombus).[15]

Indicates the process of inputting and outputting


Input/Output [15]
data,[15] as in entering data or displaying results.
Represented as a parallelogram.[14]

Indicating additional information about a step in the


program. Represented as an open rectangle with a
Annotation[14](Comment)[15]
dashed or solid line connecting it to the
corresponding symbol in the flowchart.[15]

Shows named process which is defined elsewhere.


Predefined Process [14]
Represented as a rectangle with double-struck
vertical edges.[14]

Pairs of labeled connectors replace long or confusing


On-page Connector [14]
lines on a flowchart page. Represented by a small
circle with a letter inside.[14][18]

A labeled connector for use when the target is on


Off-page Connector[14] another page. Represented as a home plate-
shaped pentagon.[14][18]

Other symbols[edit]
The ANSI/ISO standards include symbols beyond the basic shapes. Some are:[17][18]

Shape Name Description

Data File or
Data represented by a cylinder (disk drive).
Database
Single documents represented a rectangle with a wavy base.

Document

Multiple documents represented stacked rectangle with a wavy


base.

represented by a trapezoid with the longest parallel side at the top,


Manual
to represent an operation or adjustment to process that can only be
operation
made manually.

Represented by quadrilateral, with the top irregularly sloping up


Manual input
from left to right, like the side view of a keyboard.

Preparation or Represented by an elongated hexagon, originally used for steps


Initialization like setting a switch or initializing a routine.

Parallel processing[edit]
 Parallel Mode represented by two horizontal lines at the beginning or ending of simultaneous
operations[17]
For parallel and concurrent processing the Parallel Mode horizontal lines[19] or a horizontal
bar[20] indicate the start or end of a section of processes that can be done independently:

 At a fork, the process creates one or more additional processes, indicated by a bar with one
incoming path and two or more outgoing paths.
 At a join, two or more processes continue as a single process, indicated by a bar with several
incoming paths and one outgoing path. All processes must complete before the single process
continues.[20]

Software[edit]
Diagramming[edit]
Flowgorithm

Any drawing program can be used to create flowchart diagrams, but these will have no underlying
data model to share data with databases or other programs such as project management systems
or spreadsheet. Some tools such as yEd, Inkscape and Microsoft Visio offer special support for
flowchart drawing. Many software packages exist that can create flowcharts automatically, either
directly from a programming language source code, or from a flowchart description language.
There are several applications and visual programming languages[21] that use flowcharts to represent
and execute programs. Generally these are used as teaching tools for beginner students. Examples
include Flowgorithm, Raptor. LARP, Visual Logic, and VisiRule.

What are Bitwise Operators?


Bitwise operators are used for manipulating a data at the bit level, also called
as bit level programming. Bit-level programming mainly consists of 0 and 1.
They are used in numerical computations to make the calculation process
faster.

Following is the list of bitwise operators provided by 'C' programming


language:

Operator Meaning

& Bitwise AND operator

| Bitwise OR operator

^ Bitwise exclusive OR operator


~ Binary One's Complement Operator is a
unary operator

<< Left shift operator

>> Right shift operator

Bitwise operators cannot be directly applied to primitive data types such as


float, double, etc. Always remember one thing that bitwise operators are
mostly used with the integer data type because of its compatibility.

The bitwise logical operators work on the data bit by bit, starting from the least
significant bit, i.e. LSB bit which is the rightmost bit, working towards the MSB
(Most Significant Bit) which is the leftmost bit.

The result of the computation of bitwise logical operators is shown in the table
given below.

x y x&y x|y x^y

0 0 0 0 0

0 1 0 1 1

1 0 0 1 1

1 1 1 1 0

In this tutorial, you will learn-

 What are Bitwise Operators?


 Bitwise AND
 Bitwise OR
 Bitwise Exclusive OR
 Bitwise shift operators
 Bitwise complement operator

Bitwise AND
This is one of the most commonly used logical bitwise operators. It is
represented by a single ampersand sign (&). Two integer expressions are
written on each side of the (&) operator.

The result of the bitwise AND operation is 1 if both the bits have the value as
1; otherwise, the result is always 0.

Let us consider that we have 2 variables op1 and op2 with values as follows:

Op1 = 0000 1101


Op2 = 0001 1001

The result of the AND operation on variables op1 and op2 will be

Result = 0000 1001

As we can see, two variables are compared bit by bit. Whenever the value of
a bit in both the variables is 1, then the result will be 1 or else 0.

Bitwise OR
It is represented by a single vertical bar sign (|). Two integer expressions are
written on each side of the (|) operator.

The result of the bitwise OR operation is 1 if at least one of the expression has
the value as 1; otherwise, the result is always 0.

Let us consider that we have 2 variables op1 and op2 with values as follows:

Op1 = 0000 1101


Op2 = 0001 1001

The result of the OR operation on variables op1 and op2 will be

Result = 0001 1101


As we can see, two variables are compared bit by bit. Whenever the value of
a bit in one of the variables is 1, then the result will be 1 or else 0.

Bitwise Exclusive OR
It is represented by a symbol (^). Two integer expressions are written on each
side of the (^) operator.

The result of the bitwise Exclusive-OR operation is 1 if only one of the


expression has the value as 1; otherwise, the result is always 0.

Let us consider that we have 2 variables op1 and op2 with values as follows:

Op1 = 0000 1101


Op2 = 0001 1001

The result of the OR operation on variables op1 and op2 will be

Result = 0001 0100

As we can see, two variables are compared bit by bit. Whenever only one
variable holds the value 1 then the result is 0 else 0 will be the result.

Let us write a simple program that demonstrates bitwise logical operators.

#include <stdio.h>
int main()
{
int a = 20; /* 20 = 010100 */
int b = 21; /* 21 = 010101 */
int c = 0;

c = a & b; /* 20 = 010100 */
printf("AND - Value of c is %d\n", c );

c = a | b; /* 21 = 010101 */
printf("OR - Value of c is %d\n", c );

c = a ^ b; /* 1 = 0001 */
printf("Exclusive-OR - Value of c is %d\n", c );

getch();
}

Output:

AND - Value of c is 20
OR - Value of c is 21
Exclusive-OR - Value of c is 1

Bitwise shift operators


The bitwise shift operators are used to move/shift the bit patterns either to the
left or right side. Left and right are two shift operators provided by 'C' which
are represented as follows:

Operand << n (Left Shift)


Operand >> n (Right Shift)

Here,

 an operand is an integer expression on which we have to perform the


shift operation.
 'n' is the total number of bit positions that we have to shift in the integer
expression.

The left shift operation will shift the 'n' number of bits to the left side. The
leftmost bits in the expression will be popped out, and n bits with the value 0
will be filled on the right side.

The right shift operation will shift the 'n' number of bits to the right side. The
rightmost 'n' bits in the expression will be popped out, and the value 0 will be
filled on the left side.

Example: x is an integer expression with data 1111. After performing shift


operation the result will be:

x << 2 (left shift) = 1111<<2 = 0011


x>>2 (right shift) = 1111>>2 = 1100

Shifts operators can be combined then it can be used to extract the data from
the integer expression. Let us write a program to demonstrate the use of
bitwise shift operators.

#include <stdio.h>
int main() {
int a = 20; /* 20 = 010100 */
int c = 0;

c = a << 2; /* 80 = 101000 */
printf("Left shift - Value of c is %d\n", c );

c = a >> 2; /*05 = 000101 */


printf("Right shift - Value of c is %d\n", c );
return 0;
}

Output:

Left shift - Value of c is 80


Right shift - Value of c is 5

After performing the left shift operation the value will become 80 whose binary
equivalent is 101000.

After performing the right shift operation, the value will become 5 whose
binary equivalent is 000101.

Bitwise complement operator


The bitwise complement is also called as one's complement operator since it
always takes only one value or an operand. It is a unary operator.

When we perform complement on any bits, all the 1's become 0's and vice
versa.

If we have an integer expression that contains 0000 1111 then after


performing bitwise complement operation the value will become 1111 0000.

Bitwise complement operator is denoted by symbol tilde (~).

Let us write a program that demonstrates the implementation of bitwise


complement operator.

#include <stdio.h>
int main() {
int a = 10; /* 10 = 1010 */
int c = 0;
c = ~(a);
printf("Complement - Value of c is %d\n", c );
return 0;
}

Output:

Complement - Value of c is -11

Here is another program, with an example of all the operatoes discussed so


far:

#include <stdio.h>
main() {
unsigned int x = 48; /* 48 = 0011 0000 */
unsigned int y = 13; /* 13 = 0000 1101 */
int z = 0;

z =x & y; /* 0 = 0000 0000 */


printf("Bitwise AND Operator - x & y = %d\n", z );

z = x | y; /* 61 = 0011 1101 */
printf("Bitwise OR Operator - x | y = %d\n", z );

z= x^y; /* 61 = 0011 1101 */


printf("Bitwise XOR Operator- x^y= %d\n", z);

z = ~x; /*-61 = 1100 0011 */


printf("Bitwise One's Complement Operator - ~x = %d\n", z);

z = x << 2; /* 192 = 1100 0000 */


printf("Bitwise Left Shift Operator x << 2= %d\n", z );

z= x >> 2; /* 12 = 0000 1100 */


printf ("Bitwise Right Shift Operator x >> 2= %d\n", z );}

After we compile and run the program, it produces the following result:

Bitwise AND Operator - x & y = 0


Bitwise OR Operator - x | y = 61
Bitwise XOR Operator- x^y= 61
Bitwise One's Complement Operator - ~x = -49
Bitwise Left Shift Operator x << 2= 192
Bitwise Right Shift Operator x >> 2= 12

Summary
 Bitwise operators are special operator set provided by 'C.'
 They are used in bit level programming.
 These operators are used to manipulate bits of an integer expression.
 Logical, shift and complement are three types of bitwise operators.
 Bitwise complement operator is used to reverse the bits of an
expression.
A pointer is a value that designates the address (i.e., the location in memory), of some value.
Pointers are variables that hold a memory location.
There are four fundamental things you need to know about pointers:

 How to declare them (with the address operator ' & ': int *pointer = &variable; )
 How to assign to them ( pointer = NULL; )
 How to reference the value to which the pointer points (known as dereferencing, by using the
dereferencing operator ' * ': value = *pointer; )
 How they relate to arrays (the vast majority of arrays in C are simple lists, also called "1
dimensional arrays", but we will briefly cover multi-dimensional arrays with some pointers in a
later chapter).
Pointers can reference any data type, even functions. We'll also discuss the relationship of pointers
with text strings and the more advanced concept of function pointers.

Contents

 1Declaring pointers
 2Assigning values to pointers
 3Pointer dereferencing
 4Pointers and Arrays
 5Pointers in Function Arguments
 6Pointers and Text Strings
 7Pointers to Functions
 8Practical use of function pointers in C
 9Examples of pointer constructs
 10sizeof
 11External Links

Declaring pointers[edit]
Consider the following snippet of code which declares two pointers:
struct MyStruct {
int m_aNumber;
float num2;
};

int main()
{
int *pJ2;
struct MyStruct *pAnItem;
}

Lines 1-4 define a structure. Line 8 declares a variable which points to an int, and line 9 declares a
variable which points to something with structure MyStruct. So to declare a variable as something
which points to some type, rather than contains some type, the asterisk ( * ) is placed before the
variable name.
In the following, line 1 declares var1 as a pointer to a long and var2 as a long and not a pointer to
a long. In line 2, p3 is declared as a pointer to a pointer to an int.

long * var1, var2;


int ** p3;

Pointer types are often used as parameters to function calls. The following shows how to declare a
function which uses a pointer as an argument. Since C passes function arguments by value, in order
to allow a function to modify a value from the calling routine, a pointer to the value must be passed.
Pointers to structures are also used as function arguments even when nothing in the struct will be
modified in the function. This is done to avoid copying the complete contents of the structure onto
the stack. More about pointers as function arguments later.

int MyFunction( struct MyStruct *pStruct );

Assigning values to pointers[edit]


So far we've discussed how to declare pointers. The process of assigning values to pointers is next.
To assign the address of a variable to a pointer, the & or 'address of' operator is used.

int myInt;
int *pPointer;
struct MyStruct dvorak;
struct MyStruct *pKeyboard;

pPointer = &myInt;
pKeyboard = &dvorak;

Here, pPointer will now reference myInt and pKeyboard will reference dvorak.
Pointers can also be assigned to reference dynamically allocated memory. The malloc() and calloc()
functions are often used to do this.

#include <stdlib.h>
/* ... */
struct MyStruct *pKeyboard;
/* ... */
pKeyboard = malloc(sizeof *pKeyboard);

The malloc function returns a pointer to dynamically allocated memory (or NULL if unsuccessful).
The size of this memory will be appropriately sized to contain the MyStruct structure.
The following is an example showing one pointer being assigned to another and of a pointer being
assigned a return value from a function.

static struct MyStruct val1, val2, val3, val4;

struct MyStruct *ASillyFunction( int b )


{
struct MyStruct *myReturn;

if (b == 1) myReturn = &val1;
else if (b==2) myReturn = &val2;
else if (b==3) myReturn = &val3;
else myReturn = &val4;

return myReturn;
}

struct MyStruct *strPointer;


int *c, *d;
int j;

c = &j; /* pointer assigned using & operator */


d = c; /* assign one pointer to another */
strPointer = ASillyFunction( 3 ); /* pointer returned from a function. */
When returning a pointer from a function, do not return a pointer that points to a value that is local to
the function or that is a pointer to a function argument. Pointers to local variables become invalid
when the function exits. In the above function, the value returned points to a static variable.
Returning a pointer to dynamically allocated memory is also valid.

Pointer dereferencing[edit]

The pointer p points to the variable a.

To access a value to which a pointer points, the * operator is used. Another operator, the -
> operator is used in conjunction with pointers to structures. Here's a short example.

int c, d;
int *pj;
struct MyStruct astruct;
struct MyStruct *bb;

c = 10;
pj = &c; /* pj points to c */
d = *pj; /* d is assigned the value to which pj points, 10 */
pj = &d; /* now points to d */
*pj = 12; /* d is now 12 */

bb = &astruct;
(*bb).m_aNumber = 3; /* assigns 3 to the m_aNumber member of astruct */
bb->num2 = 44.3; /* assigns 44.3 to the num2 member of astruct */
*pj = bb->m_aNumber; /* equivalent to d = astruct.m_aNumber; */

The expression bb->m_aNumber is entirely equivalent to (*bb).m_aNumber . They both access


the m_aNumber element of the structure pointed to by bb . There is one more way of dereferencing
a pointer, which will be discussed in the following section.
When dereferencing a pointer that points to an invalid memory location, an error often occurs which
results in the program terminating. The error is often reported as a segmentation error. A common
cause of this is failure to initialize a pointer before trying to dereference it.
C is known for giving you just enough rope to hang yourself, and pointer dereferencing is a prime
example. You are quite free to write code that accesses memory outside that which you have
explicitly requested from the system. And many times, that memory may appear as available to your
program due to the vagaries of system memory allocation. However, even if 99 executions allow
your program to run without fault, that 100th execution may be the time when your "memory
pilfering" is caught by the system and the program fails. Be careful to ensure that your pointer offsets
are within the bounds of allocated memory!
The declaration void *somePointer; is used to declare a pointer of some nonspecified type. You
can assign a value to a void pointer, but you must cast the variable to point to some specified type
before you can dereference it. Pointer arithmetic is also not valid with void * pointers.

Pointers and Arrays[edit]


Up to now, we've carefully been avoiding discussing arrays in the context of pointers. The interaction
of pointers and arrays can be confusing but here are two fundamental statements about it:

 A variable declared as an array of some type acts as a pointer to that type. When used by itself,
it points to the first element of the array.
 A pointer can be indexed like an array name.
The first case often is seen to occur when an array is passed as an argument to a function. The
function declares the parameter as a pointer, but the actual argument may be the name of an array.
The second case often occurs when accessing dynamically allocated memory. Let's look at
examples of each. In the following code, the call to calloc() effectively allocates an array of struct
MyStruct items.

float KrazyFunction( struct MyStruct *parm1, int p1size, int bb )


{
int ix; //declaring an integer variable//
for (ix=0; ix<p1size; ix++) {
if (parm1[ix].m_aNumber == bb )
return parm1[ix].num2;
}
return 0.0f;
}

/* ... */
struct MyStruct myArray[4];
#define MY_ARRAY_SIZE (sizeof(myArray)/sizeof(*myArray))
float v3;
struct MyStruct *secondArray;
int someSize;
int ix;
/* initialization of myArray ... */
v3 = KrazyFunction( myArray, MY_ARRAY_SIZE, 4 );
/* ... */
secondArray = calloc( someSize, sizeof(MyStruct) );
for (ix=0; ix<someSize; ix++) {
secondArray[ix].m_aNumber = ix *2;
secondArray[ix].num2 = .304 * ix * ix;
}

Pointers and array names can pretty much be used interchangeably. There are exceptions. You
cannot assign a new pointer value to an array name. The array name will always point to the first
element of the array. In the function KrazyFunction above, you could however assign a new value
to parm1, as it is just a pointer to the first element of myArray. It is also valid for a function to return a
pointer to one of the array elements from an array passed as an argument to a function. A function
should never return a pointer to a local variable, even though the compiler will probably not
complain.
When declaring parameters to functions, declaring an array variable without a size is equivalent to
declaring a pointer. Often this is done to emphasize the fact that the pointer variable will be used in a
manner equivalent to an array.

/* two equivalent function definitions */


int LittleFunction( int *paramN );
int LittleFunction( int paramN[] );

Now we're ready to discuss pointer arithmetic. You can add and subtract integer values to/from
pointers. If myArray is declared to be some type of array, the expression *(myArray+j) , where j is
an integer, is equivalent to myArray[j] . So for instance in the above example where we had the
expression secondArray[i].num2, we could have written that as *(secondArray+i).num2 or more
simply (secondArray+i)->num2 .
Note that for addition and subtraction of integers and pointers, the value of the pointer is not
adjusted by the integer amount, but is adjusted by the amount multiplied by the size (in bytes) of the
type to which the pointer refers. One pointer may also be subtracted from another, provided they
point to elements of the same array (or the position just beyond the end of the array). If you have a
pointer that points to an element of an array, the index of the element is the result when the array
name is subtracted from the pointer. Here's an example.

struct MyStruct someArray[20];


struct MyStruct *p2;
int idx;

.
/* array initialization .. */
.
for (p2 = someArray; p2 < someArray+20; ++p2) {
if (p2->num2 > testValue) break;
}
idx = p2 - someArray;
SECTION 11.6: INTERRUPT PROGRAMMING IN C
So far all the programs in this chapter have been written in Assembly. In this section we
show how to program the 8051/52′s interrupts in 8051 C language. In reading this
section, it is assumed that you already know the material in the first two sections of this
chapter.
8051 C interrupt numbers
The 8051 C compilers have extensive support for the 8051 interrupts with two major
features as follows:
1. They assign a unique number to each of the 8051 interrupts, as shown in Table
11-4.
2. It can also assign a register bank to an ISR. This avoids code overhead due to
the pushes and pops of the RO – R7 registers.
Table 11-4: 8051/52 Interrupt Numbers in C

Example 11-14 shows how a simple interrupt is written in 8051 C.

Example 11-14
Write a C program that continuously gets a single bit of data from PI. 7 and sends it to
Pl.O, while simultanepusly creating a square wave of 200 (as period on pin P2.5. Use
timer 0 to create the square wave. Assume that XTAL = 11.0592 MHz.
Solution:
Example 11-15
Write a C program that continuously gets a single bit of data from PI. 7 and sends it to
Pl.O in the main, while simultaneously (a) creating a square wave of 200 us period on
pin P2.5, and (b) sending letter ‘A’ to the serial port. Use Timer 0 to create the square
wave. Assume that XTAL = 11.0592 MHz. Use the 9600 baud rate.
Solution:

Example 11-16
Write a C program using interrupts to do the following:
1. Receive data serially and send it to PO,
2. Read port PI, transmit data serially, and give a copy to P2,
3. Make timer 0 generate a square wave of 5 kHz frequency on PO.l.
Assume that XTAL = 11.0592 MHz. Set the baud rate at 4800.
Solution:
Example 11-17
Write a C program using interrupts to do the following:
1. Generate a 10000 Hz frequency on P2.1 using TO 8-bit auto-reload,
2. Use timer 1 as an event counter to count up a 1-Hz pulse and display it on PO. The
pulse is connected to EX1.
Assume that XTAL = 11.0592 MHz. Set the baud rate at 9600.
SUMMARY
An interrupt is an external or internal event that interrupts the microcontroller to inform it
that a device needs its service. Every interrupt has a program associated with it called
the ISR, or interrupt service routine. The 8051 has 6 interrupts, 5 of which are user-
accessible. The interrupts- are for reset: two for the timers, two for external hardware
interrupts, and a serial communication interrupt. The 8052 has an additional interrupt for
Timer 2.
The 8051 can be programmed to enable or disable an interrupt, and the interrupt priority
can be altered. This chapter showed how to program 8051/52 interrupts in both
Assembly and C languages.

C Programming Files I/O


There are a large number of functions to handle file I/O (Input Output) in C. In this
tutorial, you will learn to handle standard I/O in C using fprintf(), fscanf(), fread(), fwrite(),
fseek.and more.

In C programming, file is a place on your physical disk where information is stored.

Why files are needed?


 When a program is terminated, the entire data is lost. Storing in a file will preserve your data
even if the program terminates.
 If you have to enter a large number of data, it will take a lot of time to enter them all.
However, if you have a file containing all the data, you can easily access the contents of the file
using few commands in C.
 You can easily move your data from one computer to another without any changes.

Types of Files
When dealing with files, there are two types of files you should know about:

1. Text files
2. Binary files

1. Text files
Text files are the normal .txt files that you can easily create using Notepad or any simple
text editors.

When you open those files, you'll see all the contents within the file as plain text. You
can easily edit or delete the contents.
They take minimum effort to maintain, are easily readable, and provide least security
and takes bigger storage space.

2. Binary files
Binary files are mostly the .bin files in your computer.

Instead of storing data in plain text, they store it in the binary form (0's and 1's).

They can hold higher amount of data, are not readable easily and provides a better
security than text files.

File Operations
In C, you can perform four major operations on the file, either text or binary:

1. Creating a new file


2. Opening an existing file
3. Closing a file
4. Reading from and writing information to a file

Working with files


When working with files, you need to declare a pointer of type file. This declaration is
needed for communication between the file and program.

FILE *fptr;

Opening a file - for creation and edit


Opening a file is performed using the library function in the "stdio.h" header file:
fopen().
The syntax for opening a file in standard I/O is:

ptr = fopen("fileopen","mode")

For Example:

fopen("E:\\cprogram\\newprogram.txt","w");

fopen("E:\\cprogram\\oldprogram.bin","rb");

 Let's suppose the file newprogram.txt doesn't exist in the location E:\cprogram. The first
function creates a new file named newprogram.txt and opens it for writing as per the mode 'w'.
The writing mode allows you to create and edit (overwrite) the contents of the file.
 Now let's suppose the second binary file oldprogram.bin exists in the location E:\cprogram.
The second function opens the existing file for reading in binary mode 'rb'.
The reading mode only allows you to read the file, you cannot write into the file.

File
Mode Meaning of Mode During Inexistence of file

r Open for reading. If the file does not exist, fopen() returns NULL.

rb Open for reading in binary mode. If the file does not exist, fopen() returns NULL.

If the file exists, its contents are overwritten. If the


w Open for writing. file does not exist, it will be created.

If the file exists, its contents are overwritten. If the


wb Open for writing in binary mode. file does not exist, it will be created.

Open for append. i.e, Data is added to


a end of file. If the file does not exists, it will be created.
File
Mode Meaning of Mode During Inexistence of file

Open for append in binary mode. i.e,


ab Data is added to end of file. If the file does not exists, it will be created.

r+ Open for both reading and writing. If the file does not exist, fopen() returns NULL.

Open for both reading and writing in


rb+ binary mode. If the file does not exist, fopen() returns NULL.

If the file exists, its contents are overwritten. If the


w+ Open for both reading and writing. file does not exist, it will be created.

Open for both reading and writing in If the file exists, its contents are overwritten. If the
wb+ binary mode. file does not exist, it will be created.

a+ Open for both reading and appending. If the file does not exists, it will be created.

Open for both reading and appending


ab+ in binary mode. If the file does not exists, it will be created.

Opening Modes in Standard I/O

Closing a File
The file (both text and binary) should be closed after reading/writing.

Closing a file is performed using library function fclose().


fclose(fptr); //fptr is the file pointer associated with file to be closed.

Reading and writing to a text file


For reading and writing to a text file, we use the functions fprintf() and fscanf().
They are just the file versions of printf() and scanf(). The only difference is that, fprint
and fscanf expects a pointer to the structure FILE.

Example 1: Write to a text file using fprintf()


1. #include <stdio.h>
2. #include <stdlib.h>
3.
4. int main()
5. {
6. int num;
7. FILE *fptr;
8. fptr = fopen("C:\\program.txt","w");
9.
10. if(fptr == NULL)
11. {
12. printf("Error!");
13. exit(1);
14. }
15.
16. printf("Enter num: ");
17. scanf("%d",&num);
18.
19. fprintf(fptr,"%d",num);
20. fclose(fptr);
21.
22. return 0;
23. }
This program takes a number from user and stores in the file program.txt.

After you compile and run this program, you can see a text file program.txt created in C
drive of your computer. When you open the file, you can see the integer you entered.

Example 2: Read from a text file using fscanf()


1. #include <stdio.h>
2. #include <stdlib.h>
3.
4. int main()
5. {
6. int num;
7. FILE *fptr;
8.
9. if ((fptr = fopen("C:\\program.txt","r")) == NULL){
10. printf("Error! opening file");
11.
12. // Program exits if the file pointer returns NULL.
13. exit(1);
14. }
15.
16. fscanf(fptr,"%d", &num);
17.
18. printf("Value of n=%d", num);
19. fclose(fptr);
20.
21. return 0;
22. }
This program reads the integer present in the program.txt file and prints it onto the
screen.
If you successfully created the file from Example 1, running this program will get you
the integer you entered.
Other functions like fgetchar(), fputc() etc. can be used in similar way.

Reading and writing to a binary file


Functions fread() and fwrite() are used for reading from and writing to a file on the
disk respectively in case of binary files.

Writing to a binary file


To write into a binary file, you need to use the function fwrite(). The functions takes four
arguments: Address of data to be written in disk, Size of data to be written in disk,
number of such type of data and pointer to the file where you want to write.

fwrite(address_data,size_data,numbers_data,pointer_to_file);
Example 3: Write to a binary file using fwrite()
1. #include <stdio.h>
2. #include <stdlib.h>
3.
4. struct threeNum
5. {
6. int n1, n2, n3;
7. };
8.
9. int main()
10. {
11. int n;
12. struct threeNum num;
13. FILE *fptr;
14.
15. if ((fptr = fopen("C:\\program.bin","wb")) == NULL){
16. printf("Error! opening file");
17.
18. // Program exits if the file pointer returns NULL.
19. exit(1);
20. }
21.
22. for(n = 1; n < 5; ++n)
23. {
24. num.n1 = n;
25. num.n2 = 5*n;
26. num.n3 = 5*n + 1;
27. fwrite(&num, sizeof(struct threeNum), 1, fptr);
28. }
29. fclose(fptr);
30.
31. return 0;
32. }
In this program, you create a new file program.bin in the C drive.
We declare a structure threeNum with three numbers - n1, n2 and n3, and define it in the
main function as num.

Now, inside the for loop, we store the value into the file using fwrite().

The first parameter takes the address of num and the second parameter takes the size of
the structure threeNum.
Since, we're only inserting one instance of num, the third parameter is 1. And, the last
parameter *fptr points to the file we're storing the data.

Finally, we close the file.


Reading from a binary file
Function fread() also take 4 arguments similar to fwrite() function as above.

fread(address_data,size_data,numbers_data,pointer_to_file);

Example 4: Read from a binary file using fread()


1. #include <stdio.h>
2. #include <stdlib.h>
3.
4. struct threeNum
5. {
6. int n1, n2, n3;
7. };
8.
9. int main()
10. {
11. int n;
12. struct threeNum num;
13. FILE *fptr;
14.
15. if ((fptr = fopen("C:\\program.bin","rb")) == NULL){
16. printf("Error! opening file");
17.
18. // Program exits if the file pointer returns NULL.
19. exit(1);
20. }
21.
22. for(n = 1; n < 5; ++n)
23. {
24. fread(&num, sizeof(struct threeNum), 1, fptr);
25. printf("n1: %d\tn2: %d\tn3: %d", num.n1, num.n2, num.n3);
26. }
27. fclose(fptr);
28.
29. return 0;
30. }
In this program, you read the same file program.bin and loop through the records one by
one.
In simple terms, you read one threeNum record of threeNum size from the file pointed
by *fptr into the structure num.

You'll get the same records you inserted in Example 3.


Getting data using fseek()
If you have many records inside a file and need to access a record at a specific position,
you need to loop through all the records before it to get the record.

This will waste a lot of memory and operation time. An easier way to get to the required
data can be achieved using fseek().

As the name suggests, fseek() seeks the cursor to the given record in the file.

Syntax of fseek()
fseek(FILE * stream, long int offset, int whence)

The first parameter stream is the pointer to the file. The second parameter is the
position of the record to be found, and the third parameter specifies the location where
the offset starts.

Whence Meaning

SEEK_SET Starts the offset from the beginning of the file.

SEEK_END Starts the offset from the end of the file.

SEEK_CUR Starts the offset from the current location of the cursor in the file.

Different Whence in fseek

Example 5: fseek()
1. #include <stdio.h>
2. #include <stdlib.h>
3.
4. struct threeNum
5. {
6. int n1, n2, n3;
7. };
8.
9. int main()
10. {
11. int n;
12. struct threeNum num;
13. FILE *fptr;
14.
15. if ((fptr = fopen("C:\\program.bin","rb")) == NULL){
16. printf("Error! opening file");
17.
18. // Program exits if the file pointer returns NULL.
19. exit(1);
20. }
21.
22. // Moves the cursor to the end of the file
23. fseek(fptr, -sizeof(struct threeNum), SEEK_END);
24.
25. for(n = 1; n < 5; ++n)
26. {
27. fread(&num, sizeof(struct threeNum), 1, fptr);
28. printf("n1: %d\tn2: %d\tn3: %d\n", num.n1, num.n2, num.n3);
29. fseek(fptr, -2*sizeof(struct threeNum), SEEK_CUR);
30. }
31. fclose(fptr);
32.
33. return 0;
34. }
This program will start reading the records from the file program.bin in the reverse order
(last to first) and prints it.

Вам также может понравиться