Author : Christopher Sawtell
Page : << Previous 13 Next >>
of making mistakes?
There are many strategies, and over the years I have evolved my own set.
I have found that some of the most important are:
1) Document what you are going to do before yes BEFORE you write any code.
Set up the source files for the section of the program you are going to
write and put some lines of explanation as to what you intend to do in
this file. Be as precise as you can, but don't go into the detail of
explaining in English, or your First Language, exactly what every
statement does.
2) Make sure that you keep each file as small as is sensible. Some program
authors say that one should put only one function in a file. It's my
personal opinion that this is going a little bit over the top, but
certainly you should not have more than one logical activity in a source
file. It's easier to find a needle in a tiny haystack than in a big one!
3) Always use names for the objects in your program which are fully
descriptive, or at the very least are meaningful nmemonics. Put yourself
in the position of some poor soul who - a couple of years later, after you
have long finished with the project, and left the country - has been given
the task of adding a small feature to your exquisite program. Now in the
rush to get your masterpiece finished you decided to use variable names
like "a4" and "isb51" simply so that you can get the line typed a
fraction of a second faster than if you used something like
"customer_address[POST_CODE]" and "input_status_block[LOW_FUEL_TANK_#3].
The difference in ease of understanding is obvious, isn't it? However
judging by some programs which I have seen published in both magazines and
in the public domain program sources, the point has still to be made.
4) ALWAYS take great care with the layout of your code.
It's my opinion that the opening brace of ALL program structures should
be on a new line. Also if you put them in the leftmost column for structs,
enums, and initialised tables, as well as functions, then the
'find function' keystrokes ( "[[" and "]]" ) in vi will find them as well
as the functions themselves. Make sure you have the "showmatch" facility
in vi turned on. ( And watch the cursor jump when you enter the
right hand brace, bracket, or parenthesis. )
5) Try as hard as you can to have as few global variables as possible.
Some people say never have any globals. This is perhaps a bit too
severe but global variables are a clearly documented source of
programming errors. If it's impossible to perform a logical activity
in an efficient way without having a global or two, then confine
the scope of the globals to just the one file by marking the defining
declaration "static". This stops the compiler producing a symbol which
the linking loader will make available to all the files in your source.
6) Never EVER put 'magic numbers' in you source code. Always define constants
in a header file with #define lines or enum statements.
Here is an example:-
/* ----------------------------------------- */
#include <stdio.h>
enum status_input_names
{
radiator_temperature,
oil_temperature,
fuel_pressure,
energy_output,
revolutions_per_minute
};
char *stats[] =
{
"radiator_temperature",
"oil_temperature",
"fuel_pressure",
"energy_output",
"revolutions_per_minute"
};
#define NUMBER_OF_INPUTS ( sizeof ( stats ) / sizeof ( stats[0]))
main()
{
enum status_input_names name;
printf ( "Number of Inputs is: %d\n", NUMBER_OF_INPUTS );
for ( name = radiator_temperature; name < NUMBER_OF_INPUTS; name++)
{
printf ( "\n%s", stats[ name ] );
}
printf ( "\n\n" );
}
/* ----------------------------------------- */
Note that as a side effect we have available the meaningful symbols
radiator_temperature etc. as indices into the array of status input names
and the symbol NUMBER_OF_INPUTS available for use as a terminator in the
'for' loop. This is quite legal because sizeof is a pseudo-function and the
value is evaluated at the time of compilation and not when the program is
executed. This means that the result of the division in the macro is
calculated at the time of compilation and this result is used as a literal
in the 'for' loop. No division takes place each time the loop is executed.
To illustrate the point I would like to tell you a little story which is
fictitious, but which has a ring of truth about it.
Your employer has just landed what seems to be a lucrative contract with
an inventor of a completely new type of engine. We are assured that after
initial proving trials one of the larger Japanese motor manufactures is
going to come across with umpteen millions to complete the development of
the design. You are told to write a program which has to be a simple and
straightforward exercise in order to do the job as cheaply as possible.
Now, the customer - a some-what impulsive type - realises that his
engine is not being monitored closely enough when it starts to rapidly
dis-assemble itself under high speed and heavy load. You have to add a
few extra parameters to the monitoring program by yesterday morning!
You just add the extra parameters into the enumand the array of pointers
to the character strings. So:
enum status_input_names
{ radiator_temperature,
radiator_pressure,
fuel_temperature,
fuel_pressure,
oil_temperature,
oil_pressure,
exhaust_manifold_temperature
};
Let's continue the story about the Japanese purchase. Mr. Honda ( jun ) has
come across with the money and the result is that you are now a team leader
in the software section of Honda Software ( YourCountry ) Ltd. The project of
which you are now leader is to completely rewrite your monitoring program and
add a whole lot of extra channels as well as to make the printouts much more
readable so that your cheap, cheerful, and aesthetic-free program can be sold
as the "Ultimate Engine Monitoring Package" from the now world famous Honda
Real-time Software Systems. You set to work, Honda et. al. imagine that there
is going to be a complete redesign of the software at a cost of many million
Yen. You being an ingenious type have written the code so that it is easy to
enhance.
The new features required are that the printouts have to be printed with the
units of measure appended to the values which have to scaled and processed so
that the number printed is a real physical value instead of the previous
arrangement where the raw transducer output was just dumped onto a screen.
What do you have to do?
Thinking along the line of "Get the Data arranged correctly first".
You take you old code and expand it so that all the items of information
required for each channel are collected into a struct.
enum status_input_names
{
radiator_temperature,
radiator_pressure,
fuel_temperature,
fuel_pressure,
oil_temperature,
oil_pressure,
exhaust_manifold_temperature,
power_output,
torque
};
typedef struct channel
{
char *name; /* Channel Name to be displayed on screen. */
int nx; /* position of name on screen x co-ordinate.
*/
int ny; /* ditto for y */
int unit_of_measure; /* index into units of measure array */
char value;
Page : << Previous 13 Next >>