If you had to choose between

Pages: 12
Alright so I just started class again but this time the tutor is using http://www.cplusplus.com/reference/clibrary/cstdio/ instead of http://www.cplusplus.com/reference/iostream/. Personally using either one doesn't bother me but just wondering which one is used more industry standard? And well is one better than the other? I don't care which one I'm using but i find that iostream is more efficient and effective for me.

Discuss :)
Personally, I like stdio better.
Although its nice being able to directly send output to a stream by overloading operator<< (something which could also be done simply by implementing a print() function), this is what I don't like about streams:
1
2
3
4
5
6
printf("0x%08X\n",hex);
//or
std::cout <<"0x";
std::cout.width(8);
std::cout.fill('0');
std::cout <<std::hex<<hex<<std::endl;
(Also note that I had to check the reference. There's no way I'm going to remember that.)

I do, however, like string streams and not having to worry about buffer overflows to stringize numbers.
Last edited on
Both are important to be familiar with; there is still plenty of C code out there. Personally, I prefer the C++ way of doing things...
1
2
// single line:
cout << "0x" << setw( 8 ) << setfill( '0' ) << hex << n << endl;


Unfortunately since many C++ programmers these days were once C programmers, I find that printf/stdio is more common, but I strong recommend using iostreams anyway.

stdio has a lot of flexibility built into its (terse) format strings whereas the flexibility of streams comes with the penalty of extra typing (and perhaps a bit of performance, but I don't know of any useful programs that are I/O bound as the result of using streams vs. printf).

The boost::format library tries to take the best of both worlds by giving you a typesafe version of stdio's format strings, although IMHO it isn't quite the same.
All of you point out something good about both of them. I've been using stdio more the past 2 days pretty hard out. And well i must say I'm taking a big liking to the stdio :)
The only thing I hate about streams is that sprintf like functionality doesn't exist. It is great that boost provides some help but boost isn't standard c++ yet. Not all organizations are able to use boost for this reason. You can build new strings using stringstream but you cannot reformat existing strings the way sprintf does. I'll never understand why a dynamic version of sprintf wasn't included in the c++ stream implementations. Other than that, I prefer using the stream libraries over the c-style stdio.
I have one statement for you
format string exploits
.

People who use printf/scanf often don't understand the vulnerabilities the functions possess.
@kempofighter: sprintf and the link use varargs, and varargs are inherently type unsafe. C++ wants to be typesafe and for that reason C++ does not have a direct equivalent. Still, streams provide you everything that format strings provide you, just in a more verbose way.

And Zaita's argument is perhaps even a better reason not to use cstdio.
@jsmith: no they do not. They do not provide a mechanism for reformatting an existing string in the same way.
Post an example in C, and I will personally format it in C++; just to prove his point. ;)
@seymore15074

1
2
3
4
5
6
7
8
9
// Now reformat the message string to fill the format specifiers with data using
// streams.
std::string message("Label id = %d, ret val = %d");


// This is not an acceptable answer:
std::stringstream str;
str << "Label id = " << label id << "ret val = " << value;
std::string message(str.str());


I'm talking about reformatting an existing string, not building a new string from scratch. You can't use boost either.
I didn't test it, but here goes:
1
2
3
4
size_t label( message.find( "%d" ) );
size_t value( message.find( "%d", label + 1 ) );
message.replace( label, 2, label_id );
message.replace( value, 2, value );


Although, I still like the stream solution much better. I could see this case come up if you were retrieving a resource for a message from an internationalized project.
I don't get the point of that example. Why would anyone want to manually change a printf format string into the final string? It doesn't make sense. Unless, of course, that string was entered by the user, but... I don't know. It sounds roundabout.
Yeah, I'm not sure what the advantage is of reformatting an existing string vs. building a new one.

 
cout << boost::format( "Label id = %1%, ret val = %2%" ) % label_id % value;

"I don't get the point of that example. Why would anyone want to manually change a printf format string into the final string? It doesn't make sense. Unless, of course, that string was entered by the user, but... I don't know. It sounds roundabout."


Well why does boost support the operation then? Why does the windows CString class support the operation via the format function? If it doesn't make sense then why do you suppose that this is supported by those libraries? There must have been a reason. I'm not going to post a tremendous amount of code from a real project. The example was only designed to show the problem in very simple terms. So what's the problem? Obviously there are many folks out there who appreciate having that type of tool.

@jsmith: who said anything about there being an advantage? If you are designing software from the ground up (which many engineers don't have the luxury of doing) great. Use stream solutions as part of your design. If supporting existing projects where you can't just redesign the whole thing you may be stuck in a situation where you need to find a creative solution. Another example might be string reuse. Instead of lazy evaluation perhaps you want a list of strings in a lookup table and yet don't have all of the information at compile time. Instead of constructing the strings the moment you need them, some might choose to reformat an existing string from a lookup table to provide the specific values only known at run-time.
IMO. I like the printf/scanf format. The idea behind them is a very good one. Unfortunately the standard implementation is extremely dangerous and often vulnerable to software exploitation.

It's like saying. Why should I use string1 + string2 when I can just use strcpy? Sure, both achieve the same result, but strcpy isn't safe (strncpy is).

As said. Both will achieve the same result, the code generated by the compiler is likely to be similar, just more robust in the IOStream version.
kempofighter: Perhaps it would have made more sense if you had said all that from the beginning, mmh?

Anyway, it's not like it's terribly hard to implement a small format interpreter and use stringstreams and strings under the hood.

Instead of lazy evaluation perhaps you want a list of strings in a lookup table and yet don't have all of the information at compile time. Instead of constructing the strings the moment you need them, some might choose to reformat an existing string from a lookup table to provide the specific values only known at run-time.


Actually, sadly, we do this in some places in the project I work on for reasons of avoiding a massive switch() statement. But then there are built-in limitations due to the fact that the sprintf() statement has to take the arguments given to it at compile time, which means the format strings are not exactly free format.

On the drive home, it occurred to me that I don't understand your point all, but now I understand even less. Originally I thought you were saying that sprintf() allowed you to modify the format string directly. But it doesn't. sprintf() uses the format string to construct a secondary string containing the target text. Which then becomes equivalent to boost::format and stringstream.

@jsmith: I realize that sprintf creates a temporary but it performs the parsing of the original. I didn't mean to imply that the original is modified. The advantage is that sprintf does the parsing for you. Seymore gave a very specific example for a very specific situation but in know way does that provide anything like sprintf or CString::Format like behavior.

@helios: I did say everything at the beginning. How was I supposed to predict what questions you might have? I think that it is rather difficult to explain.

Let me rephrase. If you have format specifiers built into an existing string and need to later parse the string and fill them with values (without manually parsing, busting it up, and rebuilding it yourself) good luck doing this with string stream. You'll have to write your own parser to accomplish this where sprintf used to take care of that for you. With sprintf you needn't be concerned about where the "%d" is in every case so that you can do it manually. I find it very difficult to manually code all of the parsing logic that sprintf provides. Perhaps that is where the communication breakdown is occurring. If you are waiting until run time to build and format a string, no problem. If you have a function that takes an existing string and has to use it to reformat into a new string by parsing the specifiers, the boost and sprintf methods are the only good ways to do it (unless you write it completely yourself).

No, you didn't, but it doesn't matter anymore.

Well, of course. If your predecessors chose a less-than-optimal design, of course you'll be forced to make a decision: adhere to the old design, put a adapter layer and add a new design, or change the old design. That's a no-brainer.

And that's not a problem of IOstreams, but rather of the entire design of the C++ Library. None of its classes were ever designed to interact with the old interfaces of the C Library. If you didn't notice, there's also no way to convert a FILE * to an fstream. Does that suck? Possibly. But that's C++ for ya.
Last edited on
Pages: 12