Which C I/O Library Should Be Used in C++ Code

Which C I/O library should be used in C++ code?

To answer the original question:

Anything that can be done using stdio can be done using the iostream library.

Disadvantages of iostreams: verbose
Advantages of iostreams: easy to extend for new non POD types.

The step forward the C++ made over C was type safety.

  • iostreams was designed to be explicitly type safe. Thus assignment to an object explicitly checked the type (at compiler time) of the object being assigned too (generating an compile time error if required). Thus prevent run-time memory over-runs or writing a float value to a char object etc.

  • scanf()/printf() and family on the other hand rely on the programmer getting the format string correct and there was no type checking (I believe gcc has an extension that helps). As a result it was the source of many bugs (as programmers are less perfect in their analysis than compilers [not going to say compilers are perfect just better than humans]).

Just to clarify comments from Colin Jensen.

  • The iostream libraries have been stable since the release of the last standard (I forget the actual year but about 10 years ago).

To clarify comments by Mikael Jansson.

  • The other languages that he mentions that use the format style have explicit safeguards to prevent the dangerous side effects of the C stdio library that can (in C but not the mentioned languages) cause a run-time crash.

N.B. I agree that the iostream library is a bit on the verbose side. But I am willing to put up with the verboseness to ensure runtime safety. But we can mitigate the verbosity by using Boost Format Library.

#include <iostream>
#include <iomanip>
#include <boost/format.hpp>

struct X
{ // this structure reverse engineered from
// example provided by 'Mikael Jansson' in order to make this a running example

char* name;
double mean;
int sample_count;
};
int main()
{
X stats[] = {{"Plop",5.6,2}};

// nonsense output, just to exemplify

// stdio version
fprintf(stderr, "at %p/%s: mean value %.3f of %4d samples\n",
stats, stats->name, stats->mean, stats->sample_count);

// iostream
std::cerr << "at " << (void*)stats << "/" << stats->name
<< ": mean value " << std::fixed << std::setprecision(3) << stats->mean
<< " of " << std::setw(4) << std::setfill(' ') << stats->sample_count
<< " samples\n";

// iostream with boost::format
std::cerr << boost::format("at %p/%s: mean value %.3f of %4d samples\n")
% stats % stats->name % stats->mean % stats->sample_count;
}

C++ and C file I/O

Opinion

I don't know of any real project that uses C++ streams. They are too slow and difficult to use. There are several newer libraries like FastFormat and the Boost version that claim to be better there was a piece in the last ACCU Overload magazine about them. Personally I have used the c FILE library for the last 15 years or so in C++ and I can see no reason yet to change.

Speed

Here is small test program (I knock together quickly) to show the basic speed problem:

#include <stdio.h>
#include <time.h>

#include<iostream>
#include<fstream>

using namespace std;

int main( int argc, const char* argv[] )
{
const int max = 1000000;
const char* teststr = "example";

int start = time(0);
FILE* file = fopen( "example1", "w" );
for( int i = 0; i < max; i++ )
{
fprintf( file, "%s:%d\n", teststr, i );
}
fclose( file );
int end = time(0);

printf( "C FILE: %ds\n", end-start );

start = time(0);
ofstream outdata;
outdata.open("example2.dat");
for( int i = 0; i < max; i++ )
{
outdata << teststr << ":" << i << endl;
}
outdata.close();
end = time(0);

printf( "C++ Streams: %ds\n", end-start );

return 0;
}

And the results on my PC:

C FILE: 5s
C++ Streams: 260s

Process returned 0 (0x0) execution time : 265.282 s
Press any key to continue.

As we can see just this simple example is 52x slower. I hope that there are ways to make it faster!

NOTE: changing endl to '\n' in my example improved C++ streams making it only 3x slower than the FILE* streams (thanks jalf) there may be ways to make it faster.

Difficulty to use

I can't argue that printf() is not terse but it is more flexible (IMO) and simpler to understand, once you get past the initial WTF for the macro codes.

double pi = 3.14285714;

cout << "pi = " << setprecision(5) << pi << '\n';
printf( "%.5f\n", pi );

cout << "pi = " << fixed << showpos << setprecision(3) << pi << '\n';
printf( "%+.3f\n", pi );

cout << "pi = " << scientific << noshowpos << pi<< '\n';
printf( "%e\n", pi );

The Question

Yes, may be there is need of a better C++ library, may be FastFormat is that library, only time will tell.

dave

Are the global C++ I/O objects equivalent or using the C I/O streams?

When you say "C" streams, these are really the standard streams delivered to every process by the Operating System.

When a process is created the Operating System creates several low level "file descriptors" that enable input and output to it.

How these underlying standard input/output streams are implemented and in what language is down to the operating system. They have existed in operating systems since before the C language was written.

Obviously "C" provides access to those through <stdio.h> and C++ provides access to them through <iostream>.

I think that to say the C++ library uses the "C" streams may be a little misleading. If we are talking about the Standard C Library then it is unlikely that C++ will utilize those (but it is required to cooperate with them).

The underlying standard input/output streams are not part of Standard C, but they do have a long history with the C language because C was created specifically for writing Operating Systems and so the low level core of Process I/O is likely to be a C library (although it could also be assembler or another language entirely).

For example on POSIX systems there are C library headers for accessing the low level standard input/output streams that are not part of Standard C. This maybe why they are referred to as C streams in your linked documentation however the concept of standard io streams predates the C language itself.

What Standard C and Standard C++ streams do is add layers of abstraction on the raw primitives provided by the Operating System. This is generally formatting and converting between numbers and strings, character encodings , etc. C and C++ do those things rather differently.

What does C++ iostreams have to offer in comparison with the C stdio library?

There are several advantages, mostly with the << and >> operators. Getting a line isn't all that different, although being able to read it into a std::string is a considerable advantage.

C++ I/O has type safety. You don't write your parameter list as a quoted string, and then again as variables and such. You write what you're going to print once, and C++ figures out how many parameters and what type they are. When you have type mismatches, C I/O might get the I/O wrong, or even try to access protected memory.

C++ I/O is easily to extend. You can write operator<<() and operator>>() easily, once you've got a sample to copy. printf() and friends cannot be extended. You have a fixed list of format types.

C++ I/O, while it looks fairly simple at first, has a lot of programmer-accessible structure, and therefore a good C++ programmer can modify it to cover cases that C I/O can't. (Don't overuse this.)

cin or printf?

To bet on relative timings of console IO functions is imho without any real use. This is completely unpredictable (depends on environment). Console output depends completely on the speed of the console and usually not on the speed of the printf/cout. Try using local file output instead of console output.

Why doesn't C++ reimplement C standard functions with C++ elements/style?

Another more general question is why do not STL reimplementate all the standard C libraries

Because the old C libraries do the trick. The C++ standard library only re-implements existing functionality if they can do it significantly better than the old version. And for some parts of the C library, the benefit of writing new C++-implementations just isn't big enough to justify the extra standardization work.

As for atoi and the like, there are new versions of these in the C++ standard library, in the std::stringstream class.

To convert from a type T to a type U:

T in;
U out;
std::stringstream sstr(in);
sstr >> out;

As with the rest of the IOStream library, it's not perfect, it's pretty verbose, it's impressively slow and so on, but it works, and usually it is good enough. It can handle integers of all sizes, floating-point values, C and C++ strings and any other object which defines the operator <<.

EDIT:In addition,I have heard many other libraries avaliable for C++ make a lot of enhancement and extensions to STL.So does there libraries support these functions?

Boost has a boost::lexical_cast which wraps std::stringstream. With that function, you can write the above as:

U out = boost::lexical_cast<U>(in);

What makes a C standard library function dangerous, and what is the alternative?

In the old days, most of the string functions had no bounds checking. Of course they couldn't just delete the old functions, or modify their signatures to include an upper bound, that would break compatibility. Now, for almost every one of those functions, there is an alternative "n" version. For example:

strcpy -> strncpy
strlen -> strnlen
strcmp -> strncmp
strcat -> strncat
strdup -> strndup
sprintf -> snprintf
wcscpy -> wcsncpy
wcslen -> wcsnlen

And more.

See also https://github.com/leafsr/gcc-poison which is a project to create a header file that causes gcc to report an error if you use an unsafe function.

C++ Streams vs. C-style IO?

This is an heated topic.

Some people prefer to use the C++ IO since they are type-safe (you can't have divergence between the type of the object and the type specified in the format string), and flow more naturally with the rest of the C++ way of coding.

However, there is also arguments for C IO functions (my personal favorites). Some of them are:

  • They integrate more easily with localisation, as the whole string to localise is not broken up in smaller strings, and with some implementation the localizer can reorder the order of the inserted value, move them in the string, ...
  • You can directly see the format of the text that will be written (this can be really hard with stream operators).
  • As there is no inlining, and only one instance of the printf function, the generated code is smaller (this can be important in embedded environment).
  • Faster than C++ function in some implementation.

Personally, I wouldn't consider it bad practice to use C stream in C++ code. Some organisations even recommend to use them over C++ stream. What I would consider bad style is to use both in the same project. Consistency is the key here I think.


As other have noted, in a relatively large project, you would probably not use them directly, but you would use a set of wrapper function (or classes), that would best fit your coding standard, and your needs (localisation, type safety, ...). You can use one or the other IO interface to implement this higher level interface, but you'll probably only use one.


Edit: adding some information about the advantage of printf formatting function family relating to the localisation. Please note that those information are only valid for some implementation.

You can use %m$ instead of % to reference parameter by index instead of referencing them sequentially. This can be used to reorder values in the formatted string. The following program will write Hello World! on the standard output.

#include <stdio.h>
int main() {
printf("%2$s %1$s\n", "World!", "Hello");
return 0;
}

Consider translating this C++ code:

if (nb_files_deleted == 1)
stream << "One file ";
else
stream << nb_file_deleted << " files ";
stream << removed from directory \"" << directory << "\"\n";

This can be really hard. With printf (and a library like gettext to handle the localization), the code is not mixed with the string. We can thus pass the string to the localization team, and won't have to update the code if there are special case in some language (in some language, if count of object is 0, you use a plural form, in other language, there are three forms one for singular, one when there is two object and a plural form, ...).

printf (ngettext ("One file removed from directory \"%2$s\"",
"%1$d files removed from directory \"%2$s\"",
n),
n, dir);

C++ code file extension? What is the difference between .cc and .cpp

At the end of the day it doesn't matter because C++ compilers can deal with the files in either format. If it's a real issue within your team, flip a coin and move on to the actual work.



Related Topics



Leave a reply



Submit