Common Sense C - Advice and Warnings for C and C++ Programmers:Working with C++
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
New and Improved
Macros have always been one of Cs most flexible tools, and I pointed out in previous chapters how useful they are for paving over some of Cs rough spots. The power of macros and their pitfalls motivated some of the best new features of C++. Where a better C++ alternative exists, use it instead of a macro. On the other hand, youll still find some important uses of macros in C++; for example, using PTR and contents_of macros instead of *, as described in Chapter 6. You can benefit from extending these C macros to cover new C++ features, such as references. The following code uses a simple REF macro to produce easily read code:
#define REF &
...
int REF benefit_age = spouse_age;
This sure beats the non-intuitive
int& benefit_age = spouse_age;
style of coding youll find in most C++ books.
C++ offers some other clear improvements over C.Use the C++ new and delete operators instead of the malloc() and free() functions because new allocates memory based on the type of its argument, rather than on an explicit number of bytes. You can also create your own function for new operations on objects of user-defined classes.
Merrily Down the Streams
The new C++ streams I/O package provides a safer way to do I/O because the compiler will automatically generate a valid format based on the type of data being read or written. In most cases, using streams is also simpler than calling the standard C I/O functions. For both safety and convenience, where possible, use stream I/O instead of the standard C library routines. The following example shows how to write a label and value to the standard output:
cout << "x + y = " << x + y << '\n';
If x is 2 and y is 5, the output is
x + y = 7
Unfortunately, the C++ designers apparently couldnt stand the thought of introducing a useful new feature without building in at least one trap door. The following statement may look as innocent as the former, but its not:
cout << "x & y = " << x & y << '\n';
Because & has lower precedence than <, this expression is equivalent to
(cout << "x & y = " << x) & (y << '\n');
The right way to code this statement is
cout << "x & y = " << ( x & y ) << '\n';
This reinforces a C suggestion from Chapter 2 that also applies to C++: In a complex expression, use parentheses to explicitly define how the expression is evaluated. Be thankful for one thing, however. The C++ designers originally considered using < and > as the put and get operators as if there werent already enough confusion caused by the = and == operators!
Non-Plused
Now lets turn to the darker side of C++. Suppose, in the spirit of OOP, you decide to advance from standard C programming techniques to C++ techniques. One of the first ways you might try this new approach is by putting an object wrapper around calls to system functions. The example I use (based on an example in C++ Programming Style, by Tom Cargill) assumes there are system functions to iterate over a list of output files in a specified output queue. This example uses an OUTQ type that is simply a system handle for an output queue control block allocated by the system when open_outq is called. The example also uses the following OUTQ_ENTRY structure, which describes the layout of a static area filled by a call to the system-supplied next_outq_entry function:
struct OUTQ_ENTRY {
char ofile_name[NAMESIZE];
// ... Rest of OUTQ_ENTRY fields
};
Figure 8.1 shows a fragment of the OutQ class definition and the nextname member function. The following code shows how you might declare two OutQ objects and then attempt to print the first entry from both, side-by-side:
OutQ q1("PRINTER1");
OutQ q2("PRINTER2");
printf("%s\t%s\n", q1.nextname(),q2.nextname());
If the first entry in q1 was LISTINGA, and the first entry in q2 was LISTINGB, you might expect to print
LISTINGA LISTINGB
But what actually would print is
LISTINGA LISTINGA
The problem arises because the systems next_outq_entry function returns a pointer to a static area that is overwritten by the most recent call. Another way to look at it is that, even though this example uses C++s class facility to declare separate q1 and q2 objects, these objects implicitly share common storage via the next_outq_entry function.
Figure 8.2 addresses this problem by providing an OutQ member to hold the most recent output file name for each output queue. Although the code in the previous example will now work, the following code still fails to do what you might expect:
OutQ q1("PRINTER1");
printf("%s\t%s\n", q1.nextname(),q1.nextname());
Previous
Table of Contents
Next
Copyright © NEWS/400 Books
Wyszukiwarka
Podobne podstrony:
Arkusz GM 4 072 (2)Arkusz GM 7 072 (2)v 04 072069 072072 073czynnosci IT OUG UGBKUE t uj072009072 075v 04 074072 zadaniav 03 074klucz oceniania 312 [01] 01 072więcej podobnych podstron