Programmers now generally use high-level languages (HLLs) to write their programs. This gives advantages of efficiency and accuracy and hides much of the underlying complexity. Subroutines, referred to as procedures in Pascal, functions in C and methods in Java, are chunks of code which are repeatedly used as the program executes. Thus, using subroutines was originally seen simply as a method of sharing code, so as to reduce the size of programs. Special machine instructions, such as BSR or CALL, are provided which overwrite the address value in the IP so that the target of the fetch–execute sequence is switched to the subroutine code. Changing the IP in this way is effectively a ‘jmp’ or ‘goto’ operation, but the CALL instruction carries out some additional actions which will be discussed in the following sections to allow control to be returned to the place which did the call.
Where to go back to?
The use of subroutines within a single program results in the need to resolve the question of ‘where to return to?’ or ‘where did I come from?’ when a subroutine is completed. The question of where to go back to has to be answered every time a subroutine finishes.
Other programs sharing sub-routines
Further problems emerge when subroutine code is to be shared by several programs which will be executing concurrently under the control of a multitasking operating system such as Unix or Windows. As an example, on a Windows system a subroutine can be entered into a public dynamic link library (DLL) which has to be loaded into memory along with the client programs. The ‘where to return to?’ question becomes more complex because several programs may be simultaneously executing the same subroutine code! In addition, it becomes vital that none of the user programs have the opportunity to modify the shared code or interfere with variables set up by the other users.
Using subroutines does slow down the program execution speed, but this is no longer considered a serious issue for HLL programmers to worry about. You will find out the reason for this delaying effect later in the chapter. It is true that programmers now expect the compiler optimization phase to minimize the runtime of their code, but if the results are still too slow, why not buy a faster CPU?
A more important aspect of subroutines is the way they encapsulate, or package, a particular activity. When a programmer designs and writes a subroutine it is good style to identify and isolate a specific action or processing job for the subroutine to carry out. This makes it suitable (after it has been thoroughly tested) for entering into a library for others to use. Subroutine libraries are available with HLL compilers, graphics environments, operating systems interfaces, Internet support packages and many, many more. The linker brings together compiled files to create an executable program. To speed up the linking process, subroutines are compiled into object form and then entered into a library. Linkers normally scan through several such libraries while trying to find the correct subroutine to use. So, although programmers started using subroutines to reduce code size, their more significant modern role is that of providing easy access to tried and tested code. This assists with keeping down costs and speeding up the production of reliable software systems.
Published on Tue 13 January 2009 by Ben Bradshaw in Programming with tag(s): programming subroutines