072 074


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 C’s most flexible tools, and I pointed out in previous chapters how useful they are for paving over some of C’s 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, you’ll 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 you’ll 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 couldn’t 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 it’s 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 weren’t already enough confusion caused by the = and == operators! Non-Plused Now let’s 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 system’s 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 072
069 072
072 073
czynnosci IT OUG UGBKUE t uj072009
072 075
v 04 074
072 zadania
v 03 074
klucz oceniania 312 [01] 01 072

więcej podobnych podstron