Using printf in C++

J

Juha Nieminen

Scott Lurndal said:
(and many real applications do avoid templates, for whatever reasons,
like code footprint, for example).

"Real application" and "application using idiotic design principles"
are not mutually exclusive things...
 
J

Juha Nieminen

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

A format string is much handier in situations like when having all the
text of the program in separate localization files (ie. files that
specify all the text used in the program for different languages).

A parameter specifier (in other words, eg. "%2$i") is not standard,
but most systems support it. It can become especially handy in such a
situation.

You could devise your own format string and use some programmatical
searh-and-replace of parameters, but the printf format is already supported,
so you don't have to do anything additional.

Also, if extreme writing speed is required, the C I/O streams tend to be
faster than the C++ ones.
 
J

Juha Nieminen

Marcel Müller said:
The fumbling with the shift operators
primarily makes the code unreadable, especially in conjunction with
formatting.

There's a persistent claim that people keep repeating over and over
like parrots about the usage of the bit shift operators with streams
being confusing.

I have been programming in C++ both as a hobby and professionally for
the past 15 years, and I have yet to encounter and actual case where it
wasn't 100% clear which type of operator was being used.

(It's extremely difficult to even artifically create code that makes
sense and could equally well be interpreted as bit-shifting or using
C++ streams. "a << b" is a no-op if done with integrals so it alone
doesn't make sense. Conversely, streams are not assignable. Also, the
code would have to hide the actual type of those variables. This means
that the code would have to be eg. templated, and named in such a
deliberately confusing way as to not make clear what its functionality is.
In principle you could do something like "if(a << b)" and it perhaps could
be sensible as both types of operation, but then you would have to quite
artificially and carefully craft the surrounding code to also be sensible
for both situations. In short, it's actually very difficult to even
deliberately make code so obfuscated as to make it unclear which operator
is being used.)
 
M

Marcel Müller

There's a persistent claim that people keep repeating over and over
like parrots about the usage of the bit shift operators with streams
being confusing.

The major drawback are not the shift operators. It is the lack of an
output template string. To intercept the output sting with often long
C++ expressions makes things unreadable. And additional format
specifiers do that even more. The usually very compact printf syntax is
simply more clear, once you know it.
This is the reason why I dislike iostreams and use them rarely.

boost::format tries to combine the advantages of template based
formatting and type safety. But I did not yet get familiar with it so
far. Simply because I did not need to do so.


Marcel
 
B

BGB

There's a persistent claim that people keep repeating over and over
like parrots about the usage of the bit shift operators with streams
being confusing.

I have been programming in C++ both as a hobby and professionally for
the past 15 years, and I have yet to encounter and actual case where it
wasn't 100% clear which type of operator was being used.

I personally don't think it is so much a matter of being confusing, so
much as "kind of ugly looking" and "doesn't particularly have convenient
fixed-formatting options".

for example, it is nice to be able to easily specify how many characters
a string or number will take up such that everything is lined up nicely
in the output, ...


actually, I would personally like more formatting options, as the
current options are a little sparse and require some manual treatment.

examples: printing output with variable indentation (take argument and
print that many spaces or tabs), ability to use certain POSIX
extensions, ability to print a string automatically adding quotes and
character escapes, ...

maybe also a less brain-damaged "sscanf" variant would also be nice
(IOW, one capable of dealing with CSV and other data, with the kind of
character following the type indicating what is to be regarded as the
terminator, and maybe with some mechanism to specify regexes, ...).

(It's extremely difficult to even artifically create code that makes
sense and could equally well be interpreted as bit-shifting or using
C++ streams. "a<< b" is a no-op if done with integrals so it alone
doesn't make sense. Conversely, streams are not assignable. Also, the
code would have to hide the actual type of those variables. This means
that the code would have to be eg. templated, and named in such a
deliberately confusing way as to not make clear what its functionality is.
In principle you could do something like "if(a<< b)" and it perhaps could
be sensible as both types of operation, but then you would have to quite
artificially and carefully craft the surrounding code to also be sensible
for both situations. In short, it's actually very difficult to even
deliberately make code so obfuscated as to make it unclear which operator
is being used.)

not much to say on this, not seeing "confusion as the main issue".

granted, there aren't all that many other good options, given C and C++
both have relatively weak varargs (which don't themselves preserve type).

yes, variadic templates may allow better options, assuming timely
adoption of C++11.


Java originally used '+' for everything, but later also added a
"printf()" style interface ("System.out.printf" and similar).

C# was more like "time for a pile of overloaded methods"
(Console.WriteLine, ...).


for my own language currently I mostly just adopted printf (along with
"println" and similar), but the language allows more options than C
would (such as a type for allowing any arguments to be automatically fed
through "toString", ...).

I am also "on a fence" regarding adopting the rest of stdio as the file
API (but likely using a different VFS internally, vaguely sort of like
in Cygwin). there are various possible options and tradeoffs.
 
L

Luca Risolia

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

if (p_num_breakpoints> 0) {
lp->log("Breakpoint Address Core Enabled?\n");
lp->log("---------- ---------------- ---- --------\n");

for(size_t b = 0; b< p_num_breakpoints; b++) {
const s_breakpoint *bpp =&p_breakpoints;
char core[16];

if (bpp->b_core == -1) {
snprintf(core, sizeof(core), "%s", "All");
} else {
snprintf(core, sizeof(core), "%2.2d", bpp->b_core);
}
lp->log(" %2.2zu %016llx %3.3s %s\n",
b, bpp->b_address, core, bpp->b_enabled?"Yes":"No");
}
}


It's really ugly C++ code. All that stuff can be written in a more
readable, type-safe code by using std::clog (or whatever stream you
need) and standard manipulators.
 
J

jacob navia

Le 13/05/12 20:33, Luca Risolia a écrit :
All that stuff can be written in a more readable, type-safe code by
using std::clog (or whatever stream you need) and standard manipulators.

Great!

Go ahead, and show us how.
 
M

Martin Shobe

Scott said:
Rui Maciel said:
Can you provide an example where cout is useless and printf represents a
better option?

if (p_num_breakpoints > 0) {
lp->log("Breakpoint Address Core Enabled?\n");
lp->log("---------- ---------------- ---- --------\n");

for(size_t b = 0; b < p_num_breakpoints; b++) {
const s_breakpoint *bpp = &p_breakpoints;
char core[16];

if (bpp->b_core == -1) {
snprintf(core, sizeof(core), "%s", "All");
} else {
snprintf(core, sizeof(core), "%2.2d", bpp->b_core);
}
lp->log(" %2.2zu %016llx %3.3s %s\n",
b, bpp->b_address, core, bpp->b_enabled?"Yes":"No");
}
}


std::eek:stream & operator<<(std::eek:stream & os, s_breakpoint const & bpp)
{
os << setw(16);

if (bpp.b_core == -1)
{
os << "All";
}
else
{
os << setprecision(2) << bpp.b_core;
}

os << " " << setfill('0') << hex << bpp.b_address;
os << " " << bpp.b_enabled ? "Yes" : " No";

return os;
}

if (p_num_breakpoints > 0)
{
lp->log("Breakpoint Address Core Enabled?\n");
lp->log("---------- ---------------- ---- --------\n");

for (size_t b = 0; b < p_num_breakpoints; b++)
{
std::stringstream core;
core << setw(5) << setprecision(2) << b;
core << " " << p_breakpoints << "\n";

lp->log(core.str().c_str());
}
}

I don't particularly like having to use all those manipulators, but I
wouldn't call it useless. (and of course it would look a little better
if either lp or lp->log was a stream and we could get rid of the
std::stringstream).

Martin Shobe
 
L

Luca Risolia

Le 13/05/12 20:33, Luca Risolia a écrit :

Great!

Go ahead, and show us how.

if (p_num_breakpoints > 0) {
clog << "Breakpoint Address Core Enabled?\n"
"---------- ---------------- ---- --------\n";

for (size_t b = 0; b < p_num_breakpoints; b++) {
const s_breakpoint *bpp = &p_breakpoints;
ostringstream core;
bpp->b_core == -1 ? core << "All" : core << setw(3) << bpp->b_core;
clog << setfill(' ') << setw(3) << ' ' // indent
<< setfill('0') << setw(2) << b
<< setfill(' ') << setw(8) << ' '
<< setfill('0') << setw(16)
<< hex << reinterpret_cast<unsigned long>(bpp->b_address)
<< setfill(' ') << setw(2) << ' '
<< core.str().substr(0, 3) << ' '
<< setfill(' ') << setw(3) << ' '
<< boolalpha << static_cast<bool>(bpp->b_enabled)
<< '\n';
}
}

...which produces the same output as the original version with printf():

Breakpoint Address Core Enabled?
---------- ---------------- ---- --------
00 00007fff7f886a0c All false
01 00007fff7f886a0c 12 false
02 00007fff7f886a0c 123 true


With manipulators it's evident how you want to format the output. You
can pack setfill() and setw() together in an inline, user-defined
manipulator and make code even more compact and readable.

Notes: yes, reinterpret_cast<> is allowed. you may want to use boolalpha
instead of those "Yes" "No", since it comes for free.
 
M

Martin Shobe

Luca said:
Le 13/05/12 20:33, Luca Risolia a écrit :

Great!

Go ahead, and show us how.

if (p_num_breakpoints > 0) {
clog << "Breakpoint Address Core Enabled?\n"
"---------- ---------------- ---- --------\n";

for (size_t b = 0; b < p_num_breakpoints; b++) {
const s_breakpoint *bpp = &p_breakpoints;
ostringstream core;
bpp->b_core == -1 ? core << "All" : core << setw(3) << bpp->b_core;
clog << setfill(' ') << setw(3) << ' ' // indent
<< setfill('0') << setw(2) << b
<< setfill(' ') << setw(8) << ' '
<< setfill('0') << setw(16)
<< hex << reinterpret_cast<unsigned long>(bpp->b_address)
<< setfill(' ') << setw(2) << ' '
<< core.str().substr(0, 3) << ' '
<< setfill(' ') << setw(3) << ' '
<< boolalpha << static_cast<bool>(bpp->b_enabled)
<< '\n';
}
}

..which produces the same output as the original version with printf():

Breakpoint Address Core Enabled?
---------- ---------------- ---- --------
00 00007fff7f886a0c All false
01 00007fff7f886a0c 12 false
02 00007fff7f886a0c 123 true


I thought the output was supposed to look like this. (Obviously it
wouldn't take much to change it to this).

Breakpoint Address Core Enabled?
---------- ---------------- ---- --------
0 00007fff7f886a0c All No
1 00007fff7f886a0c 12 No
2 00007fff7f886a0c 123 Yes

[snip]

Martin Shobe
 
L

Luca Risolia

I thought the output was supposed to look like this. (Obviously it
wouldn't take much to change it to this).

Breakpoint Address Core Enabled?
---------- ---------------- ---- --------
0 00007fff7f886a0c All No
1 00007fff7f886a0c 12 No
2 00007fff7f886a0c 123 Yes

as I said, with regard to the "Enabled" field I have deliberately used
the boolalpha manipulator to show how to print flags as a standard
alternative.

The change to print "Yes" and "No" is:

clog << [...]
<< (bpp->b_enabled ? "Yes" : "No") // instead of boolalpha

I also confirm that the "Breakpoint" field has to look with one initial
'0' with one-digit numbers.
 
I

Ian Collins

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

if (p_num_breakpoints> 0) {
lp->log("Breakpoint Address Core Enabled?\n");
lp->log("---------- ---------------- ---- --------\n");

for(size_t b = 0; b< p_num_breakpoints; b++) {
const s_breakpoint *bpp =&p_breakpoints;
char core[16];

if (bpp->b_core == -1) {
snprintf(core, sizeof(core), "%s", "All");
} else {
snprintf(core, sizeof(core), "%2.2d", bpp->b_core);
}
lp->log(" %2.2zu %016llx %3.3s %s\n",
b, bpp->b_address, core, bpp->b_enabled?"Yes":"No");
}
}


Is %016llx a valid format string?
 
M

Martin Shobe

Luca said:
I thought the output was supposed to look like this. (Obviously it
wouldn't take much to change it to this).

Breakpoint Address Core Enabled?
---------- ---------------- ---- --------
0 00007fff7f886a0c All No
1 00007fff7f886a0c 12 No
2 00007fff7f886a0c 123 Yes

as I said, with regard to the "Enabled" field I have deliberately used
the boolalpha manipulator to show how to print flags as a standard
alternative.

The change to print "Yes" and "No" is:

clog << [...]
<< (bpp->b_enabled ? "Yes" : "No") // instead of boolalpha

I also confirm that the "Breakpoint" field has to look with one initial
'0' with one-digit numbers.

Yes, you are correct.

Martin Shobe
 
B

BGB

Rui Maciel said:
Scott Lurndal wrote:

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?

if (p_num_breakpoints> 0) {
lp->log("Breakpoint Address Core Enabled?\n");
lp->log("---------- ---------------- ---- --------\n");

for(size_t b = 0; b< p_num_breakpoints; b++) {
const s_breakpoint *bpp =&p_breakpoints;
char core[16];

if (bpp->b_core == -1) {
snprintf(core, sizeof(core), "%s", "All");
} else {
snprintf(core, sizeof(core), "%2.2d", bpp->b_core);
}
lp->log(" %2.2zu %016llx %3.3s %s\n",
b, bpp->b_address, core, bpp->b_enabled?"Yes":"No");
}
}


Is %016llx a valid format string?


in C99 or newer, yes.

basically in means 0-padded, 16 digits, long-long, and hex (lower case).

so, if you print a constant like 12841684688557LL

the result is:
00000badf00ddead
 
I

Ian Collins

Scott Lurndal wrote:

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?



if (p_num_breakpoints> 0) {
lp->log("Breakpoint Address Core Enabled?\n");
lp->log("---------- ---------------- ---- --------\n");

for(size_t b = 0; b< p_num_breakpoints; b++) {
const s_breakpoint *bpp =&p_breakpoints;
char core[16];

if (bpp->b_core == -1) {
snprintf(core, sizeof(core), "%s", "All");
} else {
snprintf(core, sizeof(core), "%2.2d", bpp->b_core);
}
lp->log(" %2.2zu %016llx %3.3s %s\n",
b, bpp->b_address, core, bpp->b_enabled?"Yes":"No");
}
}


Is %016llx a valid format string?


in C99 or newer, yes.

basically in means 0-padded, 16 digits, long-long, and hex (lower case).

so, if you print a constant like 12841684688557LL

the result is:
00000badf00ddead

Um, it doesn't appear to work as advertised:

int main()
{
printf( "%016llx %d\n", &main, 42 );
}

gives

0000002a08050a10 134511408

where

printf( "%016x %d\n", &main, 42 );

gives

0000000008050a10 42

for 32 bit builds on my platform (Solaris). 64 bit builds are OK.
 
I

Ian Collins

Um, it doesn't appear to work as advertised:

int main()
{
printf( "%016llx %d\n",&main, 42 );
}

gives

0000002a08050a10 134511408

where

printf( "%016x %d\n",&main, 42 );

gives

0000000008050a10 42

for 32 bit builds on my platform (Solaris). 64 bit builds are OK.

Which isn't surprising when an address is 32 bits and long long is 64.
Type safe output anyone?

:)
 
N

Nobody

for example, it is nice to be able to easily specify how many characters
a string or number will take up such that everything is lined up nicely
in the output, ...

If you want that capability, you need to use the *wprintf functions. The
non-wide versions measure the field width in "char"s (even for e.g.
"%ls"), which isn't of much use with a multi-byte encoding.
maybe also a less brain-damaged "sscanf" variant would also be nice

If you get to decide the data format, *scanf is sufficient. If you don't
get to decide the data format, anything short of the capabilities provided
by e.g. lex+yacc is just tinkering with the boundary between "sufficient"
and "if only they had added just this one extra feature".
 
8

88888 Dihedral

Nobodyæ–¼ 2012å¹´5月14日星期一UTC+8上åˆ11時20分55秒寫é“:
If you want that capability, you need to use the *wprintf functions. The
non-wide versions measure the field width in "char"s (even for e.g.
"%ls"), which isn't of much use with a multi-byte encoding.


If you get to decide the data format, *scanf is sufficient. If you don't
get to decide the data format, anything short of the capabilities provided
by e.g. lex+yacc is just tinkering with the boundary between "sufficient"
and "if only they had added just this one extra feature".

Don't forget uni-code support in any descent high level languages.
 
B

BGB

On 05/14/12 05:25 AM, Scott Lurndal wrote:
Scott Lurndal wrote:

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?



if (p_num_breakpoints> 0) {
lp->log("Breakpoint Address Core Enabled?\n");
lp->log("---------- ---------------- ---- --------\n");

for(size_t b = 0; b< p_num_breakpoints; b++) {
const s_breakpoint *bpp =&p_breakpoints;
char core[16];

if (bpp->b_core == -1) {
snprintf(core, sizeof(core), "%s", "All");
} else {
snprintf(core, sizeof(core), "%2.2d", bpp->b_core);
}
lp->log(" %2.2zu %016llx %3.3s %s\n",
b, bpp->b_address, core, bpp->b_enabled?"Yes":"No");
}
}

Is %016llx a valid format string?


in C99 or newer, yes.

basically in means 0-padded, 16 digits, long-long, and hex (lower case).

so, if you print a constant like 12841684688557LL

the result is:
00000badf00ddead

Um, it doesn't appear to work as advertised:

int main()
{
printf( "%016llx %d\n", &main, 42 );
}

gives

0000002a08050a10 134511408

where

printf( "%016x %d\n", &main, 42 );

gives

0000000008050a10 42

for 32 bit builds on my platform (Solaris). 64 bit builds are OK.


this is because a pointer is not a long-long.
on 32-bit targets, it is generally a 32 bit type.

otherwise, it would be necessary to cast to a 64 bit integer type,
probably as a 2-step cast as the compiler may complain about a
single-step cast from a pointer to an integer of a different size.
 
B

BGB

If you want that capability, you need to use the *wprintf functions. The
non-wide versions measure the field width in "char"s (even for e.g.
"%ls"), which isn't of much use with a multi-byte encoding.

dunno.

probably the majority of cases where this sort of formatted output is
being done are ASCII-only anyways.

otherwise, there could be a use for, say, a version which uses UTF-8 (I
primarily use UTF-8 rather than UTF-16 or similar, because UTF-8 tends
to be more compact).

If you get to decide the data format, *scanf is sufficient. If you don't
get to decide the data format, anything short of the capabilities provided
by e.g. lex+yacc is just tinkering with the boundary between "sufficient"
and "if only they had added just this one extra feature".

it is not "one or the other" IMO, and personally I haven't used lex+yacc
either (as they offer little real obvious advantages over a hand-written
tokenizer and recursive descent parser, but come with a number of
drawbacks).


in the simple case, there are many forms of data which are seperated by
trivial, non-space deliminators.

CSV is a major example, where ',' is the main seperator.
some other formats use ':' or ';' for a similar role.

a sscanf-like function could easily deal with this case, if it did not
assume whitespace was the separator.


regexes or PEG parsers could be used in many more advanced cases.
 

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

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top