Output integers formatted like +0012345

W

Woody

I want to output integers in the form sNNNN, where s is the sign (+ or
-) and N are digits, always 4 of them. For example, if the integer is
123, the output I want is +0123; if the integer is -1, output should
be -0001.

cout << [something] << integer

is what I'm looking for, but I can't find anything that puts integers
into this form simply. It seems possible to do this using 'internal'
in conjunction with setw(4) and setfill('0'), but this is really ugly.
Is there anything simpler in standard C++?
 
V

Venu Yanamandra

I want to output integers in the form sNNNN, where s is the sign (+ or
-) and N are digits, always 4 of them. For example, if the integer is
123, the output I want is +0123; if the integer is -1, output should
be -0001.

cout << [something] << integer

is what I'm looking for, but I can't find anything that puts integers
into this form simply. It seems possible to do this using 'internal'
in conjunction with setw(4) and setfill('0'), but this is really ugly.
Is there anything simpler in standard C++?

Hi Woody,

I found setw and setfill as a good choice.

---
#include <iostream>
#include <iomanip>

using namespace std;

class tstClass;
ostream& operator<<(ostream &, tstClass &);

class tstClass
{
friend ostream& operator<<(ostream&, tstClass&);
public:
int i;
static int width;
};

int tstClass::width = 6; /* Set the value of default print width */

ostream& operator<<(ostream &os, tstClass &t1)
{
char sign = (t1.i<0)?'-':'+';
int ii = (t1.i<0)?-(t1.i):(t1.i);
os << "Integer in " << tstClass::width << " width and Sign is: {" <<
sign << setw(tstClass::width) << setfill('0') << ii << "}" << endl;
return(os);
}

int main()
{
tstClass t1, t2;
t1.i = -35;
t2.i = 28;
cout << t1;
cout << t2;
}
 
J

Jorgen Grahn

I want to output integers in the form sNNNN, where s is the sign (+ or
-) and N are digits, always 4 of them. For example, if the integer is
123, the output I want is +0123; if the integer is -1, output should
be -0001.

cout << [something] << integer

is what I'm looking for, but I can't find anything that puts integers
into this form simply.

sprintf() does it easily, so I might write a wrapper object:

struct SNNNN {
explicit SNNNN(int n);
};
ostream& operator<< (ostream&, const SNNNN&);

cout << SNNNN(integer)

This method has a bonus feature: it lets you control what happens if
you try to print 31415927 or 1e9. I don't think iostreams or even
sprintf() have.

/Jorgen
 
J

James Kanze

I want to output integers in the form sNNNN, where s is the
sign (+ or -) and N are digits, always 4 of them. For example,
if the integer is 123, the output I want is +0123; if the
integer is -1, output should be -0001.
cout << [something] << integer
is what I'm looking for, but I can't find anything that puts
integers into this form simply. It seems possible to do this
using 'internal' in conjunction with setw(4) and setfill('0'),
but this is really ugly. Is there anything simpler in
standard C++?

Presumably, there is some reason for wanting to output integers
in this format. That is, the output corresponds to some sort of
logical entity. If the name of that logical entity is foo, then
the obvious solution is:
cout << foo << integer;
All you have to do is write the manipulator foo (which isn't
that hard---you've already explained what you need in it).

In a well written program, almost all output will be preceded by
some sort of logical manipulator, telling the reader what type
of output is being done, and telling ostream how to format it.
If for some reason, you change the formatting of that logical
entity, you modify the manipulator, and all of the output
automatically adjusts.

The obvious exception is when that logical entity is already
encapsulated in a class. In that case, you don't need the
manipulator, since the operator<< for the class takes care of
all of the formatting for that entity.
 
J

jacob navia

Le 24/11/10 22:52, Woody a écrit :
I want to output integers in the form sNNNN, where s is the sign (+ or
-) and N are digits, always 4 of them. For example, if the integer is
123, the output I want is +0123; if the integer is -1, output should
be -0001.

cout<< [something]<< integer

is what I'm looking for, but I can't find anything that puts integers
into this form simply. It seems possible to do this using 'internal'
in conjunction with setw(4) and setfill('0'), but this is really ugly.
Is there anything simpler in standard C++?

sprintf(buf,"+04d",number);


Forget about cout, and use something that works without spending hours
of development.

But of course, why make it simple when you can waste days in making it
complicated?


jacob
 
J

jacob navia

Le 25/11/10 23:37, jacob navia a écrit :
Le 24/11/10 22:52, Woody a écrit :
I want to output integers in the form sNNNN, where s is the sign (+ or
-) and N are digits, always 4 of them. For example, if the integer is
123, the output I want is +0123; if the integer is -1, output should
be -0001.

cout<< [something]<< integer

is what I'm looking for, but I can't find anything that puts integers
into this form simply. It seems possible to do this using 'internal'
in conjunction with setw(4) and setfill('0'), but this is really ugly.
Is there anything simpler in standard C++?

sprintf(buf,"+04d",number);


Forget about cout, and use something that works without spending hours
of development.

But of course, why make it simple when you can waste days in making it
complicated?


jacob

A whole program looks like this:

#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[])
{
printf("With width 6 that gives: {%+05d}\n",atoi(argv[1]));
}

No error checking. Size with gcc -Os: 8750 bytes`

The program proposed by Mr Yanamandra.venu above
([email protected]) does the same but takes much more
time and effort and weights 10000 bytes, 12% more.

I just can't understand the design idea behind C++ cout stuff.
It just sucks...
 
I

Ian Collins

A whole program looks like this:

#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[])
{
printf("With width 6 that gives: {%+05d}\n",atoi(argv[1]));
}

No error checking. Size with gcc -Os: 8750 bytes`

Now there's a problem straight away, where will you do the error
checking? With this scheme, explicitly for every value to be output.
The program proposed by Mr Yanamandra.venu above
([email protected]) does the same but takes much more
time and effort and weights 10000 bytes, 12% more.

OK, try a expansion of Jorgen Grahn's proposal, with blunt instrument
error checking:

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <iostream>

struct SNNNN
{
const int n;

explicit SNNNN( int i ) : n(i) { assert(abs(n) < 10000); }
};

std::eek:stream& operator<<( std::eek:stream& out, const SNNNN& sn )
{
char tmp[8];
sprintf( tmp, "%+05d", sn.n );
return out << tmp;
}

int main(int argc,char *argv[])
{
std::cout << SNNNN( atoi(argv[1]) ) << std::endl;
}

9836 bytes, with automatic range checking, which could easily be
expanded to include checking the sting passed was a valid number (we all
know atoi should be avaided, don't we?).
I just can't understand the design idea behind C++ cout stuff.
It just sucks...

Try using printf in a template!

Another case is adding a new type; to add printing of size_t, the C
standard and printf had to be updated, with iostreans, just add a new
pair of operators.
 
J

James Kanze

Le 24/11/10 22:52, Woody a écrit :
I want to output integers in the form sNNNN, where s is the sign (+ or
-) and N are digits, always 4 of them. For example, if the integer is
123, the output I want is +0123; if the integer is -1, output should
be -0001.
cout<< [something]<< integer
is what I'm looking for, but I can't find anything that puts integers
into this form simply. It seems possible to do this using 'internal'
in conjunction with setw(4) and setfill('0'), but this is really ugly.
Is there anything simpler in standard C++?
sprintf(buf,"+04d",number);

Forget about cout, and use something that works without spending hours
of development.

Except that as written, it doesn't work, so it must not be as
simple as you pretend. (FWIW, I've almost never seen code using
sprintf which was correct.)
But of course, why make it simple when you can waste days in
making it complicated?

If you accept that it might not work, and that the program will
never, never be modified, then why bother, yes. Most people
can't accept those two conditions, which effectively excludes
sprintf.
 
J

jacob navia

Le 29/11/10 18:36, James Kanze a écrit :
Le 24/11/10 22:52, Woody a écrit :
I want to output integers in the form sNNNN, where s is the sign (+ or
-) and N are digits, always 4 of them. For example, if the integer is
123, the output I want is +0123; if the integer is -1, output should
be -0001.
cout<< [something]<< integer
is what I'm looking for, but I can't find anything that puts integers
into this form simply. It seems possible to do this using 'internal'
in conjunction with setw(4) and setfill('0'), but this is really ugly.
Is there anything simpler in standard C++?
sprintf(buf,"+04d",number);

Forget about cout, and use something that works without spending hours
of development.

Except that as written, it doesn't work, so it must not be as
simple as you pretend. (FWIW, I've almost never seen code using
sprintf which was correct.)

You have never seen code using sprintf that was correct.

You haven't seen a lot of code then.

If you accept that it might not work, and that the program will
never, never be modified, then why bother, yes. Most people
can't accept those two conditions, which effectively excludes
sprintf.


sprintf works perfectly. Besides, you can modify any code that uses
sprintf as you wish, for instance to change the 04 to 06 or whatever
the width you want.

You use vi, emacs, notepad, whatever and you modify the code. Or you
mean to say that code that uses sprintf is automatically marked
"read only"?

If you want parametrization of the sprintf call you can hide it in
a function/class, but in most cases you just print it and forget
it.
 
I

Ian Collins

Le 29/11/10 18:36, James Kanze a écrit :

You have never seen code using sprintf that was correct.

You haven't seen a lot of code then.

Now I worried. According to James, there are potentially 8646 incorrect
uses just in the kernel of the OS I'm using......
 
J

jacob navia

Le 30/11/10 11:12, Ian Collins a écrit :
Now I worried. According to James, there are potentially 8646 incorrect
uses just in the kernel of the OS I'm using......

I think he says it doesn't work because I use +04d and should have used
+06d, or a trivial correction like that.

I do not know if C++ recognizes snprintf. I should have used that
instead of sprintf, but the result is very much the same.

The advantage (as I see it) of the printf family is that they use
a ad-hoc language (the sprintf specifications) and a run time
intepreter of those specifications (the printf function) to
format the data, what is more flexible and less verbose that
the cout design.

jacob
 
J

Joe Greer

I think the issue is that sprintf is rather soft around the edges. For
example, if you have your %04d format specifier and pass a value of 123456,
then you get all 6 digits rather than the 4 requested. Negative numbers
might give surprising results as well. Further, sprintf itself can be
easily fooled about types vs format specifiers though some compilers will
check this for you. Personally, I prefer format strings to the coding
required for streaming operators, but everyone is allowed their own
favorites. I would probably really prefer some third alternative more like
..Net format strings where you can also have user defined format specifiers
if you want. You might want to check out boost format for another way to
get this kind of formatting with type safety thrown in, though I don't know
that they solve the problem with value validation.

joe
 
J

James Kanze

Le 29/11/10 18:36, James Kanze a écrit :
Le 24/11/10 22:52, Woody a écrit :
I want to output integers in the form sNNNN, where s is the sign (+ or
-) and N are digits, always 4 of them. For example, if the integer is
123, the output I want is +0123; if the integer is -1, output should
be -0001.
cout<< [something]<< integer
is what I'm looking for, but I can't find anything that puts integers
into this form simply. It seems possible to do this using 'internal'
in conjunction with setw(4) and setfill('0'), but this is really ugly..
Is there anything simpler in standard C++?
sprintf(buf,"+04d",number);
Forget about cout, and use something that works without spending hours
of development.
Except that as written, it doesn't work, so it must not be as
simple as you pretend. (FWIW, I've almost never seen code using
sprintf which was correct.)
You have never seen code using sprintf that was correct.
You haven't seen a lot of code then.

I've probably seen a lot more than you. I worked on Unix
kernels for awhile, and have worked on more than one project
with millions of lines of source code. And while I actually
wrote code once which did use sprintf in a way that couldn't
fail, it was a lot more work than using an ostringstream.
sprintf works perfectly.

Sometimes. You can never be sure of it, however.
Besides, you can modify any code that uses
sprintf as you wish, for instance to change the 04 to 06 or whatever
the width you want.

Yup. Or the %d to %s (without changing the type of the
argument being formatted, of course). That's part of the
problem with it.
You use vi, emacs, notepad, whatever and you modify the code. Or you
mean to say that code that uses sprintf is automatically marked
"read only"?
If you want parametrization of the sprintf call you can hide it in
a function/class, but in most cases you just print it and forget
it.

Until the program crashes.
 
J

James Kanze

You have never seen code using sprintf that was correct.
You haven't seen a lot of code then.
[/QUOTE]
Now I worried. According to James, there are potentially 8646 incorrect
uses just in the kernel of the OS I'm using......

If there are any uses of sprintf in the kernel of an OS, I'd be
very worried. (To begin with, what happens when the
implementation of sprintf uses some kernel functionality which
calls sprintf. Kernel code doesn't use user level library
functions, period.)

But then, there are OS's where quality and robustness isn't
a criteria. (One notable one is still written in C, rather than
in C++.)
 
J

James Kanze

Le 30/11/10 11:12, Ian Collins a écrit :
I think he says it doesn't work because I use +04d and should
have used +06d, or a trivial correction like that.

No. It doesn't work because you don't dynamically scale the
buffer according to the format string and the type of number.
It doesn't work because you can change the format string and the
type of the number without changing the size of the buffer. it
doesn't work because, fundamentally, you have no real means of
knowing how big the buffer has to be. (Actually, your precise
example doesn't work because it always outputs "+04d", rather
than number. A simple typo. But its sensitivity to such things
is precisely why sprintf is not something a professional would
use in production code.)

In some cases, you can do something like:

char buffer[6];
assert(number < 1000 && number > -1000);
sprintf(buffer, "%+04d", number);

In others, you can allocate the buffer dynamically, or at least
with the size determined by some compile time expression, so
that at least you don't get bit the day someone changes the type
(or you upgrade to 64 bit machine), but you're still at the
mercy of someone modifying the format.
 
J

jacob navia

Le 30/11/10 17:57, James Kanze a écrit :
No. It doesn't work because you don't dynamically scale the
buffer according to the format string and the type of number.

Thisis not necessary. Just use a buffer of size 30 and you will
be safe even in 64 bit environments with 64 bit ints...

But obviously, whymake it simple when you can make it more
and more obscure.
It doesn't work because you can change the format string and the
type of the number without changing the size of the buffer.

See above.
it
doesn't work because, fundamentally, you have no real means of
knowing how big the buffer has to be.


If you assume 64 bit numbers, the decimal representation of a
64 bit number can't exceed 20 digits. That's very simple
math... By using a 30 bytebuffer you are 100 % SURE that
it will ALWAYS work. Yes, in 10 years you *could* have
128 bit numbers but I doubt that they would be just
ints". Besides, "ints" have stayed 32 bits in all machines
that I have seen.


(Actually, your precise
example doesn't work because it always outputs "+04d", rather
than number. A simple typo. But its sensitivity to such things
is precisely why sprintf is not something a professional would
use in production code.)


I posted a working example without any typo that you do not mention.
In some cases, you can do something like:

char buffer[6];
assert(number< 1000&& number> -1000);
sprintf(buffer, "%+04d", number);

In others, you can allocate the buffer dynamically, or at least
with the size determined by some compile time expression, so
that at least you don't get bit the day someone changes the type
(or you upgrade to 64 bit machine), but you're still at the
mercy of someone modifying the format.

If you insist on saving 24 bytes local variable space... that
could happen to you.

And if somebody modifies the format without modifying the buffer
he (she) introduces a bug, and you can't do anything about that.

But if you develop your own awfully complicated solution you expose
yourself to MORE potential problems...

Look at this:

ostream& operator<<(ostream &os, tstClass &t1)
{
char sign = (t1.i<0)?'-':'+';
int ii = (t1.i<0)?-(t1.i):(t1.i);
os << "Integer in " << tstClass::width << " width and Sign is: {" <<
sign << setw(tstClass::width) << setfill('0') << ii << "}" << endl;
return(os);
}


Note that you set the output width to 6. Now you have introduced a bug
in some OTHER procedure that had set the width to 9 several functions
before and that now it will output an INCORRECT result, truncated
to 6 places.

The same with the other parameters. As far as I know, there is no way to
save the values of those global parameters and restore them to their
original values, what is one of the BIGGEST problems in your approach.

Care to answer why you did not see that OBVIOUS BUG?

:)

jacob navia
 
J

jacob navia

Le 30/11/10 17:50, James Kanze a écrit :
But then, there are OS's where quality and robustness isn't
a criteria. (One notable one is still written in C, rather than
in C++.)

Well, you are speaking nonsense here. C++ is not used very much for OS
writing...

C is used, and Unix was always written in C since ages. Assembler
is used. But not C++.
 
J

jacob navia

Le 30/11/10 17:47, James Kanze a écrit :
Sometimes. You can never be sure of it, however.


Yup. Or the %d to %s (without changing the type of the
argument being formatted, of course). That's part of the
problem with it.



Until the program crashes.

Look at this C++ solution:
ostream& operator<<(ostream &os, tstClass &t1)
{
char sign = (t1.i<0)?'-':'+';
int ii = (t1.i<0)?-(t1.i):(t1.i);
os << "Integer in " << tstClass::width << " width and Sign is: {" <<
sign << setw(tstClass::width) << setfill('0') << ii << "}" << endl;
return(os);
}

You see the bug in it?

It changes the width to 6. This will make ALL OTHER procedures that
use this stream to cut their output at 6... introducing a BUG.

Did I say that "ostream doesn't work"?

No. But this complicated solution has ALSO pitfalls (as everything).

There is NO silver bullet, just different kinds of problems. The C++
solution will not crash but produce wrong output, what is much
more difficult to detect and debug than a simple crash.

You seem to despise simple solutions and propose always complicated
over-engineered solutions to simple problems. I disagree with your
viewpoint because it introduces MORE problems than what it pretends to
"solve"
 
J

jacob navia

Le 30/11/10 15:53, Joe Greer a écrit :
I think the issue is that sprintf is rather soft around the edges. For
example, if you have your %04d format specifier and pass a value of 123456,
then you get all 6 digits rather than the 4 requested. Negative numbers
might give surprising results as well. Further, sprintf itself can be
easily fooled about types vs format specifiers though some compilers will
check this for you.

Yes, most of them analyze those format strings.

What is important to remembre is that the C++ solutions changes the
ostream parameters, and THAT introduces further bugs.

If another output procedure had set the width to 9 before calling your
output routine, after running your routine it will output only
the last 6 digits without any warning or overflow indication!!!


At least sprintf does NOT truncate the output. The difference
between
100 123 456

and 123 456

is 100 million... Nothing in the output will indicate that
the output is truncated.

The sprintf design decision (not truncating the output)
is much better than the ostream (silently truncating)
 
I

Ian Collins

If there are any uses of sprintf in the kernel of an OS, I'd be
very worried.

I should have been more precise, s/kernel/kernel consolidation/ which
includes the user land where the sprintf calls reside. The point still
remains, I can see several thousand correct uses of sprintf.
But then, there are OS's where quality and robustness isn't
a criteria. (One notable one is still written in C, rather than
in C++.)

Can you name a desktop or server OS that isn't written in C?
 

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

Similar Threads


Members online

No members online now.

Forum statistics

Threads
473,982
Messages
2,570,186
Members
46,744
Latest member
CortneyMcK

Latest Threads

Top