Hi,
when I need to execute a general clean-up procedure (inside of a
function) just before the function returns -- how do I do that when
there are several returns spread over the whole function?
There are different details:
- follow the roule that no fuction should be have more lines
of code than a screen (print) page can show.
This makes it easier to understund the code
and helps debugging the whole program
- if the function goes too big for the rule above you tries
to make too much details at once. Then break down the whole
job in multiple little functions (even as each function
gets called only one).
- define the style for each function:
- has only ONE return in case its job gets done well
but multiple returns on errors.
This will be the case when the awaited result is:
"done anything well"
- has only one return in case its job fails
but multiple returns its job is done well.
This will be the case when the natural result of that job
is: "something fails as expected"
- has only exactly ONE return point
This is the case when even something fails the total
work has to be done and either NO fail at all occurs
or even NO result is needed.
depending if you can identify WELL as ONE single value
or its easier to define ONE single value as error indicator.
- define the most significant value as return value and
less significant ones (when there are some)
as parameter.
The function result will be
- only an indicator of success/fail (like pointer/NULL pointer)
optionally another parameter gives more details about errors
- a pure error code
- one value indicates success (e.g. 0)
any other gives the error number
In both cases you needs on the calling point only one if
to differ between success and fail of this step
- Splitting out a whole switch statement
into a separate function using the roles above.
This helps you to differ WHAT from HOW.
- You may even have a need to split out each (or some)
case into own functions to separate out "WHAT is to do"
from "HOW is it done"
- in general:
when a function gets too big to follow the first role
it is easy too see that you have too much work for a
single function.
Spitting out "WHAT" from "HOW" is to do helps you
to get your mind clean. Define a function for each "What"
to hide details from the "WHAT".
If "HOW" is too much again split this detail again.
This method will allow you
- debug each detail alone by writing a debug main(),
compile little function alone, test it using different
testdata.
- debug outer functions using theyr input leaving out
inner functions during trace because you knows they
should work already.
- split up each function in at least 3 logical blocks
whereas each can be empty:
1. init
A check input parameters when needed
B allocate resources the fuction and its helper functions
needs - but only if A was successfull
a memory/files needed for internal work
b memory/files needed to return to caller
2. do the work only when 1. successfull
3. clean up
free all resources you have not return to the caller,
a close/remove files (only when they are created/opened
successfull).
Attention: the result from close() and rmove()
may change your result from success to fail!
b free memory (free() allows to be called with NULL
pointers! So you can blindly free() anything.
Each of 1-3, A+B, a+b can be done one or more helper fuctions.
if, if - else, if - else - if is a wounderful constunct - but
only if you gets your code so structured that they are NOT
got nested deep. Deep nesting points you to a design error.
Roll up the WHAT/HOW levels from scratch at this point.
At least your whole program will follow the rule:
I WHAT is to do.
Describes a (sub)job on what kind on work is to do
but lefts open HOW it gets done by calling II as function
for each step. When the WHAT is too complex the (sub)job
gets broken into a bit more detail of functions I.
This will describe your program in a logical way
without holding up with detail questions.
II HOW is it done
This does the real work in detail. In general you would
go recursively to I to get more description of WHAT
by working out mathematical formulas, formatting data
and so on. You'll break down to I again when during design
you sees more need to describe WHAT is to do and recursive
into II when the HOW is too complex to get done in a single
page.
So evakuating the body of nested or long wounded loops (for, while,
do) into functions of theyr own will remove lots of details from your
brain until you writes the details. You shortens switch statements to
"some different work based on this" is done. You shortens if and else
to "when this condition then this kind of work is to do" without
showing the details until you writes them.
This helps you to avoid lots of
- nested if and else if statements
- gotos (destroying the flow)
- higher nested for/while/do statements
in hiding details fom the flow until you needs them really.
I'm learned that techics in times whereas
- memory was only in amout of KB instead MB available
- assembly was the highest possible programming language
by
- thinking in objects builded of objects builded....
but nothing on help available than my brain to build them
(is there another method to get hudge programms in low memory?)
- need of reuse so many functions as possible
because having every time to less memory available
- having real time work on CPUs having not even 1 single MHz (instead
of xxGHz today).
--
Tschau/Bye
Herbert
Visit
http://www.ecomstation.de the home of german eComStation
eComStation 1.2 Deutsch ist da!