Team-FLY |
Error handling is a key issue in writing reliable systems programs. When you are writing a function, think in terms of that function being called millions of times by the same application. How do you want the function to behave? In general, functions should never exit on their own, but rather should always indicate an error to the calling program. This strategy gives the caller an opportunity to recover or to shut down gracefully. Functions should also not make unexpected changes to the process state that persist beyond the return from the function. For example, if a function blocks signals, it should restore the signal mask to its previous value before returning. Finally, the function should release all the hidden resources that it uses during its execution. Suppose a function allocates a temporary buffer by calling malloc and does not free it before returning. One call to this function may not cause a problem, but hundreds or thousands of successive calls may cause the process memory usage to exceed its limits. Usually, a function that allocates memory should either free the memory or make a pointer available to the calling program. Otherwise, a long-running program may have a memory leak ; that is, memory "leaks" out of the system and is not available until the process terminates. You should also be aware that the failure of a library function usually does not cause your program to stop executing. Instead, the program continues, possibly using inconsistent or invalid data. You must examine the return value of every library function that can return an error that affects the running of your program, even if you think the chance of such an error occurring is remote . Your own functions should also engage in careful error handling and communication. Standard approaches to handling errors in UNIX programs include the following.
In general, functions should never exit on their own but should always report an error to the calling program. Error messages within a function may be useful during the debugging phase but generally should not appear in the final version. A good way to handle debugging is to enclose debugging print statements in a conditional compilation block so that you can reactivate them if necessary. Example 2.10The following code segment shows an example of how to use conditional compilation for error messages in functions. #define DEBUG /* comment this line out for no error messages */ int myfun(int x) { x++; #ifdef DEBUG fprintf(stderr, "The current value of x is %d\n", x); #endif } If you comment the #define line out, the fprintf statement is not compiled and myfun does no printing. Alternatively, you can leave the #define out of the code completely and define DEBUG on the compiler line as follows . cc -DDEBUG ... Most library functions provide good models for implementing functions. Here are guidelines to follow.
|
Team-FLY |