Common Sense C - Advice and Warnings for C and C++ Programmers:Practical Pointers
Common Sense C - Advice & Warnings for C and C++ Programmers
by Paul Conte
29th Street Press
ISBN: 1882419006 Pub Date: 10/01/92
Previous
Table of Contents
Next
By using typedef, local variables instead of dereferenced parameters, array notation, and various macros and functions, you can reduce the number of places where you must code *, whether in declarations or as the dereferencing operator. Because * isnt a very intuitive symbol for contents of (in most 3X/400 programmers experience, * stands for multiplication, a multicharacter wildcard, or the start of a S/38 or AS/400 special value), you can improve your C programs readability by minimizing its use. To further improve readability, you may even want to define the three macros in Figure 6.11 PTR, contents_of, and address_of.
Figure 6.11 Pointer-Related Macros
#define PTR *
#define contents_of( x ) ( * ( x ) )
#define address_of( x ) ( & ( x ) )
Figure 6.12 shows a revised version of the fees function, using PTR and contents_of. (Instead of using PTR, you could define an int_ptr_t typedef for integer pointers.) Figure 6.13 shows how you can use the address_of macro to emphasize what are being passed as arguments to fees.
Figure 6.12 Improved fees Function Using PTR and contents_of Macros
void function fees( int PTR rfee,
int PTR afee,
const int age,
const int income ) {
int reg_fee = contents_of( rfee );
int act_fee = contents_of( afee );
reg_fee += age >= 60 ? ( income < 50000 ? 0 : 50 ) :
( income < 50000 ? 100 : 200 );
act_fee += age >= 60 ? ( income < 50000 ? 10 : 20 ) :
( income < 50000 ? 30 : 40 );
/*
| Return values
*/
contents_of( rfee ) = reg_fee;
contents_of( afee ) = act_fee;
Figure 6.13 Calling fees Function Using address_of Macro
int reg_fee;
int act_fee;
int age;
int income;
.
.
.
reg_fee = 100;
act_fee = 50;
.
.
.
fees( address_of( reg_fee ), address_of( act_fee ), age, income );
These macros dont provide a complete safety net for your C programs, but they can make your programs clearer and easier to check for pointer-related mistakes. If youre not sure you need such macros, or if youre worried your C code will look nonstandard with the macros and other techniques Ive suggested in this book, stop by your local bookstore and peruse the code listings in the latest C Gazette. The examples in this C programmers magazine will give you a wide sampling of how impenetrable and varied typical C code is. After reading some of the published code, youll appreciate both the necessity and the benefits of efforts to improve C readability.
One Blankety-Blank Trap After Another
It helps to know about Cs traps and pitfalls, and it never hurts to know a few arcane C rules to amaze your programming friends and baffle your boss. The next exercise serves both purposes. Read the following code slowly and carefully. Then before reading the solution, write down what you think the value of x is at the end of this sequence of statements.
float x=4.0;
float y=2.0;
float *z;
z=$amp;x;
x=y++/*z;
Did you remember that the post-increment ++ adds 1 to y after getting the value of y (2.0) to use in the expression? Did you also notice that z points to the same memory location as x and thus has the same value, 4.0? Did you come up with 2.0/4.0, or 0.5, as the result? Or did you find, deep in your C manual, that C uses greedy lexical analysis (i.e., tries to make the next identifier or operator in the input stream as long as possible) and thus treats /* as the beginning of a comment, not as the division operator followed by the dereferencing operator? The resulting expression is the same as:
x=y++ /*z
... */
So the value of x is 2.0, and the compiler digests most of the rest of the program as a comment. One absent blank (between / and *) makes a world of difference. This may seem like a contrived problem, but consider several seemingly simpler, and more likely, assignment statements:
z = &y;
x = y + *z;
x = ++ *z;
x = *z ++;
The second statement adds the value of y (2.0) and the contents of the location z points to (also 2.0) and puts the result in x. No surprises here. The third statement increments the contents of the location z points to (changing the value from 2.0 to 3.0) and assigns the new value to x. No surprises here either. But the final statement, which looks similar to the others, is actually quite different. This statement assigns 3.0 (the new value of *z) to x so far so good and then increments the address stored in z, rather than the contents of the location z points to. Because unary increment operators (++ and ) bind more tightly than the dereferencing operator (*), you have to use parentheses to apply post-increments to a dereferenced pointer:
x = (*z) ++;
Of course, if we rewrite the previous expressions using the contents_of macro,
x = y++/contents_of(z);
x = y + contents_of(z);
x = ++ contents_of(z);
x = contents_of(z) ++;
the lack of blanks and Cs tricky operator precedence arent a problem another bonus of using readability macros.
Previous
Table of Contents
Next
Copyright © NEWS/400 Books
Wyszukiwarka
Podobne podstrony:
051 060 (2)050 051v 02 051v 02 049051 053045 049v 03 051więcej podobnych podstron