049 051


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 * isn’t 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 don’t 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 you’re not sure you need such macros, or if you’re worried your C code will look “nonstandard” with the macros and other techniques I’ve suggested in this book, stop by your local bookstore and peruse the code listings in the latest C Gazette. The examples in this C programmer’s magazine will give you a wide sampling of how impenetrable and varied typical C code is. After reading some of the published code, you’ll appreciate both the necessity and the benefits of efforts to improve C readability. One Blankety-Blank Trap After Another It helps to know about C’s 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 C’s tricky operator precedence aren’t a problem — another bonus of using readability macros. Previous Table of Contents Next Copyright © NEWS/400 Books

Wyszukiwarka

Podobne podstrony:
051 060 (2)
050 051
v 02 051
v 02 049
051 053
045 049
v 03 051

więcej podobnych podstron