16.12 C- Versus C- Style IO

I l @ ve RuBoard

16.12 C- Versus C++- Style I/O

Both C- and C++- style I/O have their own features and quirks . In this section we'll discuss some of the differences between these two systems.

16.12.1 Simplicity

Let's say we want to write a simple checkbook program. We need to print an account statement. We need some code to print each line of the account statement (date, check number, payee, and amount).

In C the print statement looks like:

 std::printf("%2d/%2d/%02d %4d: %-40s %f6.2\n",    check.date.month, check.date.day, check.date.year,    check.number, check.payee, check.amount); 

In C++ the print statement is:

 std::cout << setw(2) << check.date.month << '/' <<              setw(2) << check.date.day << '/' <<              setw(2) << setfill('0') << check.date.year << ' ' <<              setw(4) << check.number << ':' <<               setw(40) << setiosflags(std::ios::left) <<                           check.payee <<              resetiosflags(std::ios::left) << ' ' <<              setw(6) << setprecision(2) <<               setiosflags(std::ios::fixed) <<               check.amount <<               setw(0) << '\n'; 

From this example we can clearly see that the C-style I/O is more compact. It is not clear that compact is better. This author prefers the compact style of the C std::printf functions, while many others prefer the verbosity of the C++ I/O system. Besides if you're C++ programmers, you probably should program in C++ and not bring legacy I/O systems into the mix.

Although it looks like C is more compact, things are not as obvious as they look. A well-designed date class would have its own output operator. Thus we can simplify our C++ code down to:

 std::cout << check.date <<                  setw(4) << check.number << ':' <<                   setw(40) << setiosflags(std::ios::left) <<                               check.payee <<                  resetiosflags(std::ios::left) << ' ' <<                  setw(6) << setprecision(2) <<                   setiosflags(std::ios::fixed) <<                   check.amount <<                   setw(0) << '\n'; 

But this assumes that only the date has an output operator. If we designed our check class correctly, it should have one as well. This means that our code now has been simplified down to:

 std::cout << check << '\n'; 

Now this doesn't mean that complexity has gone away. It's merely been moved from outside the class to inside it.

This example serves to illustrate one of the key differences between C and C++. In C-style I/O, the information on how to manipulate the data (in this case, how to print it) is contained outside the data itself. In C++ it's possible to put the manipulation code and the data into a single class.

If we are writing out our checkbook information in only one place, the C version may be simpler and easier to work with. So for simple programs, you may want to consider using C-style I/O. But suppose that we wanted to print out the data to a number of places. If we used C-style I/O, we would have to replicate our format code all over the place or create a small function to do the printing. With C++'s classes, we can keep the printing information in one logical place. (As a person who's just had to rewrite all the C-style format statements in a rather large piece of code, I can tell you that putting the formatting information in one place, the object, has some advantages.)

16.12.2 Reliability

When you use C++-style I/O, the system automatically detects the type of the variable and performs the approbate conversion. It's impossible to get the types wrong.

With C-style I/O, it's easy to get the arguments to a std::printf mixed up, resulting in very strange results when you run the program. What's worse is that most compilers do not check std::printf calls and warn you if you make a mistake.

One special C I/O function you should be aware of is std::gets . This function gets a line from standard input with no bounds-checking . So:

 std::gets(line); 

is exactly like:

 std::fgets(line, INFINITY, stdin); 

If there are too many characters in an input line, the std::gets function will cause a buffer overflow and trash memory. This single function and its lack of bounds-checking has to be responsible for more crashes and security holes than any other single C function. [2] You should never use it. You can get in enough trouble with the more reliable C functions without having to play Russian roulette with this one.

[2] As I am writing this, Microsoft has just released a security patch to Windows XP to fix a buffer overflow bug.

16.12.3 Speed

I've done some benchmarks on C and C++ I/O for binary files. In general I've found the C I/O to be much faster. That's because the C I/O system is less flexible and has to deal with less overhead than the C++ system.

I'm not talking about formatted I/O, just raw binary I/O. If you do formatted I/O in either system, you can expect your speed to go down tremendously. It's the single slowest system in the entire C and C++ library.

16.12.4 Which Should You Use?

Which I/O system is best? That depends on a large number of factors. First of all, any system you know is always going to be easier to use and more reliable than a system you don't know.

However, if you know both systems, C-style I/O is good for the simple stuff. If you're not doing anything fancy with classes and just want to write simple formatted reports , the C I/O system will do the job. However, for larger jobs, the C++-object oriented system with its object-oriented I/O system handles complexity and organizes complex information much better than C-style I/O.

But if you're learning I/O for the first time, I suggest that you stick with one I/O system, the C++ one. Learn C-style I/O only if you're forced to. (Say, for instance, you have to maintain some legacy code that uses the old C-style system.)

I l @ ve RuBoard


Practical C++ Programming
Practical C Programming, 3rd Edition
ISBN: 1565923065
EAN: 2147483647
Year: 2003
Pages: 364

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net