Using printf in C++

S

Seneika

Hi,

I'm new to C++, but I already did some work with C (in fact, I do my
every day work with Fortran).

I really like 'printf' (i.e., I got used to it) and I'm not liking
'cout' that much.

In the book I'm following (C++ Primer Plus) the author advocates the
power of cout, but he doesn't say that using printf in C++ is wrong.

So I ask: Is it wrong or not-advisable to use printf (more precisely
fprintf) in C++ programs to do the I/O? My work involves constantly
reading/writing data files with specific number formatting. Should I
learn how to use cout more effectivelly (RTFM to the end) or can I
stick with printf.

Thanks,
Seneika.
 
M

Marcel Müller

I really like 'printf' (i.e., I got used to it) and I'm not liking
'cout' that much.

Well, the iostream library is one of the very first C++ libraries. I
would call it broken by design. The fumbling with the shift operators
primarily makes the code unreadable, especially in conjunction with
formatting.
In the book I'm following (C++ Primer Plus) the author advocates the
power of cout, but he doesn't say that using printf in C++ is wrong.

printf is still part of the C++ runtime. But take care about it's
variants. While printf and fprintf is usually safe, sprintf is
error-prone. Using inconsistent format characters is not the primary
problem. Some compilers print warnings about that. But buffer overflows
are difficult to handle with sprintf. In general one should avoid char*
for strings in C++. (const char* in contrast is often fine.)

In fact I prefer printf syntax in almost all cases of logging and human
readable formatting. To be save I use a sprintf variant that safely
prints into a string class with matching storage, std::string or
whatever. vsnprintf, supported by many platforms makes this quite easy
to implement.
So I ask: Is it wrong or not-advisable to use printf (more precisely
fprintf) in C++ programs to do the I/O?

If it fits your needs: use it.
My work involves constantly
reading/writing data files with specific number formatting. Should I
learn how to use cout more effectivelly (RTFM to the end) or can I
stick with printf.

You won't get happy with the iostream library if you inter-operate with
files of Fortran number crunchers.


Marcel
 
B

BGB

Well, the iostream library is one of the very first C++ libraries. I
would call it broken by design. The fumbling with the shift operators
primarily makes the code unreadable, especially in conjunction with
formatting.

yep.

it is also notable that, for the most part, languages which followed
after C++ still tended towards more C-like interfaces regarding printing
(function or method, often with some sort of formatting string, and
arguments following after said string).

I personally much prefer printf as well, but granted I have also written
much more C code than I have C++ code, which could be a factor.

printf is still part of the C++ runtime. But take care about it's
variants. While printf and fprintf is usually safe, sprintf is
error-prone. Using inconsistent format characters is not the primary
problem. Some compilers print warnings about that. But buffer overflows
are difficult to handle with sprintf. In general one should avoid char*
for strings in C++. (const char* in contrast is often fine.)

generally agreed.

although, I think the issue isn't so much about "char *" vs "const char
*" vs "std::string" or similar, but often the (generally unsafe)
practice of regarding strings as mutable buffers.

in my case, I tend to regard strings as immutable by default, but
usually the const keyword is not used given the compiler often taking
issue with const and non-const char-pointers being mixed (implicit
conversions, ...), so more often the "const" is implied. this could be
fixed (by switching to consistently using "const char *", or probably a
typedef thereof), but the codebase is large enough to where doing so
would be a hassle.


however, sadly, a lot of code in my case still uses a lot of temporary
char arrays as buffers as well, which albeit unsafe, there are few
"good" alternatives in the general case (at least in plain C land).

however, it is a convention in my case to (usually) make some effort to
avoid running past the end of the buffer (typically by comparing the
current target-pointer against a target-buffer-end pointer). this is at
least generally safer (if applied consistently), without some of the
potentially steep costs of some other options (higher implementation
complexity, poor performance, ...).

for, example rather than simply something like:
while(*s)*t++=*s++;
a person can instead write something like:
while(*s && t<te)*t++=*s++;
which is not particularly more complicated, or significantly slower, but
can have the advantage of not running past the end of the buffer (given
by 'te').


or, if the code in question is C++, a person can also just use std::string.

In fact I prefer printf syntax in almost all cases of logging and human
readable formatting. To be save I use a sprintf variant that safely
prints into a string class with matching storage, std::string or
whatever. vsnprintf, supported by many platforms makes this quite easy
to implement.

yeah.

snprintf and vsnprintf are good idea, but have the drawback of being
absent on some compilers (including MSVC last I checked).

it is possible to work around this and some of the other issues by
implementing a custom version of the printing function, but this is
admittedly kind of a hassle (as is implementing all of the various
formatting options).

If it fits your needs: use it.

yep.


I personally believe there is no real "right" or "wrong" in regards to
programming, rather it is more about costs and benefits, ...

one thing I ran across before was a convention known as "SWOT"
(Strengths, Weaknesses, Opportunities, Threats), which is IMO a
moderately more useful convention for classifying various development
options.

I often use this internally, but often end up expressing them more in
terms of a pros/cons convention (so: pros=strengths+opportunities, and
cons=weaknesses+threats), usually because this is easier to express
(don't need 4 categories).

so, the "good" option is that with more good points, and the "bad"
option is that with more bad points, rather than some sort of law etched
in stone somewhere ("all X much be done using Y" or similar).

similarly, anything which can be implemented is possible (even if
potentially counter-intuitive), because programming is about writing
things (and not merely invoking language features), ...


granted, I have gotten into pointless arguments with people about these
sorts of things. ( I wrote some about it, but decided to leave it out as
it was starting to look like a bit of a pointless rant, which will often
cause people to try to argue about it, which isn't really productive. )

You won't get happy with the iostream library if you inter-operate with
files of Fortran number crunchers.

yep, among other things...
 
N

Nobody

So I ask: Is it wrong or not-advisable to use printf (more precisely
fprintf) in C++ programs to do the I/O?

The main downside is that fprintf() only works for a FILE*, while a C++
ostream can be an fstream, stringstream, an implementation-specific
extension or a user-defined class. You can build your own ostream on top
of a FILE* but you can't do the reverse without using platform-specific
extensions such as fopencookie() or funopen().

Another advantage of C++ streams is that their locale handling is more
flexible. Being able to imbue() a locale to a stream is preferable to
having to continually switch the global locale to avoid writing files with
decimal commas. And the C locale can't be sync'd to a C++ locale which
uses custom facets (or, for that matter, which sets individual facets
rather than categories).
My work involves constantly
reading/writing data files with specific number formatting. Should I
learn how to use cout more effectivelly (RTFM to the end) or can I
stick with printf.

Personally, I tend to define reader/writer classes to avoid spreading
implementation details all around the code. Changing the implementation
from <iostream> to <cstdio> or vice versa would be trivial.
 
I

Ian Collins

Why? Can't you do this without much problems if you call

std::ios::sync_with_stdio(true);

first?

You can, but why would you want to?

Mixing C and C++ streaming operations is just as much bad style as bad
practice.
 
I

Ian Collins

cout is useless in real applications.

That's nonsense.

How would you use printf reliably in templates? Or aren't templates
part of "real applications"?

How would you use printf with user defined types (even something a
simple as std::complex)? Or aren't user defined types part of "real
applications"?
 
B

BGB

That's nonsense.

How would you use printf reliably in templates? Or aren't templates part
of "real applications"?

How would you use printf with user defined types (even something a
simple as std::complex)? Or aren't user defined types part of "real
applications"?

I don't actually agree with the quoted statement either, so this is not
a defense of his position.


but, it is actually possible to write an intermediate function to
convert the data into a string, which may be in turn printed with printf
or similar (this is actually fairly common in many C applications).

so, something like:
printf("%s\n", FooType_toString(obj));

or, in my case:
printf("%s\n", dyToString(obj));

where dyToString uses a custom dynamic typesystem (obj needs to be a
dynamically-typed object handle), and looks up the vtable for the type,
and invokes its toString method (if available, otherwise it uses a
"default" handler, which spits out something like "#<typename:address>").


so, the apparent assertion that printf can't be used to print
user-defined types isn't really correct either.
 
I

Ian Collins

I don't actually agree with the quoted statement either, so this is not
a defense of his position.

but, it is actually possible to write an intermediate function to
convert the data into a string, which may be in turn printed with printf
or similar (this is actually fairly common in many C applications).

so, something like:
printf("%s\n", FooType_toString(obj));

or, in my case:
printf("%s\n", dyToString(obj));

But why would you want to?
so, the apparent assertion that printf can't be used to print
user-defined types isn't really correct either.

I didn't intend to claim that it can't, merely that it's cumbersome. I
think you have just proved my point!
 
B

BGB

But why would you want to?

because this strategy also works in C, and doesn't require implementing
an alternative printing interface.

I didn't intend to claim that it can't, merely that it's cumbersome. I
think you have just proved my point!

it works, and there are plenty more cumbersome things a person could be
doing.
 
J

Jorgen Grahn

Well, the iostream library is one of the very first C++ libraries. I
would call it broken by design. The fumbling with the shift operators
primarily makes the code unreadable,

IME it makes the code /readable/, once you deal with the types which
printf() can't print.

const FooClient& c = ...
const in6_addr& addr = ...

os << "Client " << c << " connected from " << addr << '\n';

compared to

char buf[INET6_ADDRSIZE];
std::fprintf(f, "Client %s connected from %s\n",
to_string(c).c_str(),
inet_ntop(INET6_ADDR, (void*)addr, buf, sizeof buf));
especially in conjunction with formatting.

I never got familiar with that stuff, either. Perhaps others like it.

/Jorgen
 
G

Guest

That's nonsense.

How would you use printf reliably in templates? Or aren't templates
part of "real applications"?

How would you use printf with user defined types (even something a
simple as std::complex)? Or aren't user defined types part of "real
applications"?

I've printed latitudes and longitudes and havine an operator<< makes life a lot easier
 
G

Guest

But why would you want to?


I didn't intend to claim that it can't, merely that it's cumbersome. I
think you have just proved my point!

iomanip always looks pretty cumbersome to me
 
J

Jeff Flinn

You can, but why would you want to?

Mixing C and C++ streaming operations is just as much bad style as bad
practice.

Oh, let's say I'm using several 3rd party libraries that I've no control
over.

Jeff
 
R

Rui Maciel

Scott said:
Use it and be happy. cout is useless in real applications.

Can you provide an example where cout is useless and printf represents a
better option?


Rui Maciel
 
I

Ian Collins

Actually, I'd use snprintf, and return string objects.

In a template? How?
(and many real applications do avoid templates, for whatever reasons,
like code footprint, for example).

Code footprint is only an issue if you don't know what you are doing.
 
I

Ian Collins

because this strategy also works in C, and doesn't require implementing
an alternative printing interface.

But this strategy breaks in templates. Consider a specialised numeric
type: with streaming operators it behaves like a built in type (which is
one of the original design goals of C++), with your strategy it does not.
 
D

Dombo

Op 12-May-12 22:58, Rui Maciel schreef:
Can you provide an example where cout is useless and printf represents a
better option?

IMO the big advantage of printf over std::cout is formatting, with
std::cout formatting is so clumsy and messy that I consider it to be
somewhere between impractical and useless.

For just about every other aspect I prefer std::cout (or streams), but
mostly because of the type safety and extendability this mechanism
provides. The boost format library seams to be a nice compromise, though
I don't have first hand experience with it.
 
B

BGB

But this strategy breaks in templates. Consider a specialised numeric
type: with streaming operators it behaves like a built in type (which is
one of the original design goals of C++), with your strategy it does not.

admittedly, thus far I have rarely used templates much either.

most of what I had done in C++ had been making use of operator
overloading and making use of classes.
 
L

Luca Risolia

Well, the iostream library is one of the very first C++ libraries. I
would call it broken by design. The fumbling with the shift operators
primarily makes the code unreadable, especially in conjunction with
formatting.

The inserter "<<" and the extractor ">>" had been deliberately chosen
for a number of reasons:

1. it was not possible to invent new lexical elements
2. other operators like "=" or ">" and "<" were considered inappropriate
for I/O. In particular, the former has a bad order of operator
association i.e. cout=a=b means cout=(a=b) instead of (cout=a)=b.
3. many preferred two distinct operators for insertion and extraction,
and ">>" and "<<" are symmetric symbols as the operations they represent.
4. operator >> and operator << have a priority low enough to write
expressions such as cout << a+b*c << '\n' without the need of parenthesis.
5. they are rarely used with base types

That said, in my opinion they do make the code more readable and
compact, above all in presence of both standard and user-defined
manipulators, For example:

cout << "My secret is: " << decrypt(pswd) << my_secret << clear << '\n';

Obviously, there is no way to do that with printf() in a single line.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top