Most programmers don't know what to do when they encounter
a bug in their program. I believe that the cause for this is the fact that
most programmers don't know how a computer works. Face the facts people,
if you think that you're a programmer (*) then you should know how your
computer works - being a programmer is about making a computer work! If
you don't know the basic concepts behind the operation of your machine
then you've got little hope of ever writing good code.
(*) Some people who are employed to write computer programs say
that they are not programmers. I can't understand this attitude, if you
deliver food to someone's table then you're a waiter, if you answer phones
then you're a receptionist, if you write computer programs (or parts therof)
then you're a programmer. If you think otherwise then you're probably trying
to delude yourself because you think of programmers as "geeks" - see a
therapist.
Here's a list of the basics that I think you should know to be a competant
C programmer:
- The basic concepts of assembly programming - you don't have to be able
to write assembler code, just understand it when you see it.
- How an internal Harvard architecture CPU works, how the stack operates,
and what registers do and how they are used.
- How a computer motherboard works. What transistors, VLSI chips, and buses
do. The relative speeds of the different types of storage (registers, cache,
and RAM).
- How a computer system works, how all the basic bits of hardware work and
talk to each other. The programming interfaces for all of them. You don't
need to know the details, just the concepts involved - I couldn't write
a device driver for any piece of hardware, but I know how they all
work.
- How your OS works. If you don't know how the OS works then you will never
have a clue about how to get it to efficiently do what you want. Knowing
how other OSs than the one you're programming work is always handy, but
not absolutely required.
- How your compiler works. You should know about the different parts of a
C compiler (the pre-processor, parser, assembler, and the linker) and what
they do.
Some quick tips on really debugging a program (as opposed to making
it limp through a demo only to crash in production).
- Compile and test the code in both debugging and non-debugging modes of
the compiler. Most compilers will shift memory around in strange ways in
debugging mode to try and shake out bugs. When you do an optimising compile
all the objects are crammed together in memory so a single byte memory
over-run will generally cause something bad to happen. This means that
if you want a reliable program then it may be a good idea to test in both
methods. Of course a well written program won't be so terribly buggy. But
in any moderately sized program you'll have at least 3 programmers, and
at least 2 of them probably won't be able to write such great code. ;-)
Alternatively you may find that when writing a small program on your own
you may be a bit slack when designing and coding and need to do extra debugging
to compensate. Also note that some compilers such as Microsoft Visual C++
don't find errors such as uninitialised data when compiling in debug mode!
This is not a bug in VC as such, just an issue you have to work with when
trying to fix code on that platform.
Some programmers will go through a program and test each module
in both debug and optimised builds and use the version that works. This
is one of the dumbest things you can do as a programmer. If you do this
you shouldn't expect any large program that you write to work, and you
shouldn't expect job security either! If you are a professional programmer
then you will want to have all the code you write work in both debug and
release builds. That is because you will want to fix every bug you
find.
- Your code should ideally compile with no warnings. If it does give a
warning that you can't prevent then you should either use a #pragma to disable
the warning for that section of code or comment the code as to why you
had to do this. You might think that warnings are a minor thing, but at
least 10% of all warnings are serious issues that may be bugs in your code.
Also some warnings may be latent bugs, IE they won't actually be bugs at
the time you write the code, but if you change some of the context it may
do something you don't expect or desire.
Remember - the person who wrote the compiler is probably a
better programmer than you ever dream of becomming. They put the warnings
in for good reasons, although you may not understand them!
- Memory analysis checking is always a good idea. If your compiler supports
this (AFAIK they all do now) then you should turn it on for debugging builds.
Also be very wary of doing things such as using your own macros to wrap
the new/delete operators in C++ or the malloc()/free() functions in C,
such macros can prevent memory analysis with compilers such as IBM's VisualAge
C++.
- Enable profiling for debugging builds as a matter of course. Profiling
allows a record to be kept of the order that functions are called which
allows you to trace through the program's execution in the way you might
do when running in a debugger. However any timing dependant program (IE
anything that runs serial ports, network communications, or multiple threads)
won't work the same way when being single-stepped in the debugger. Such
programs can be run under the profiler and crash for you giving you a good
trace of what went wrong (as opposed to running without crashing under
the debugger which gives you little chance to discover the problem).
Copyright © 1998 Russell
Coker, may be distributed freely.