I'm trying to format numbers using C++ streams and am having trouble with the sign character being placed after the fill instead of before. When I do this:
std::cout << std::setfill('0') << std::setw(6) << -1;
The output is
0000-1
But what I want is
-00001
With printf I can use a format like "%06d" and it works the way I expect with the sign placed before the zeroes, but I want to get the same effect in a stream and not use the old formatting functions. I can't use C++20 yet either, so std::format isn't available to me yet.
I should have looked a little longer before posting. The answer is the std::internal manipulator, which causes the padding to be done internally within the field. This works correctly:
std::cout << std::internal << std::setfill('0') << std::setw(6) << -1;
-00001
Related
I'm trying to fully understand how to use ostringstream to modernize some code that uses sprintf. The problem is in replacing test code that generates random or sequential data. Here's a simplified example:
char num[6], name[26];
sprintf(num, "%05d", i);
sprintf(name, "Customer # %d", i);
Leaving aside the minutia of length calculation, copying the result to the array and null-termination, the num conversion is straightforward:
ostringstream ostr;
ostr << setw(len) << setfill('0') << i;
For example, given i as 123, the result is "00123".
However, for the name, which is actually a mixture of a char-string and an integer, I can't figure how to replicate what sprintf appears to do so easily.
I tried variations of this:
ostr << setw(len) << left << "Customer # " << i << setfill(' ');
Given the same value for i, the result was always "Customer # 123", i.e., the integer always right justified, no matter what combination of left, right or internal, or the placement of the various parts. It seems the only solution (I haven't tried it yet), is to first concatenate the "Customer # " and the i onto a separate ostringstream and then insert that left justified to the ostr variable. Am I missing something? Is there some other way?
Correction: as discussed in the comments, in simplifying the example I overlooked a second sprintf that was actually responsible for right-padding the name. So a second output to the ostringsteam is also needed to accomplish that.
I recently had a problem creating a stringstream due to the fact that I incorrectly assumed std::setw() would affect the stringstream for every insertion, until I changed it explicitly. However, it is always unset after the insertion.
// With timestruct with value of 'Oct 7 9:04 AM'
std::stringstream ss;
ss.fill('0'); ss.setf(ios::right, ios::adjustfield);
ss << setw(2) << timestruct.tm_mday;
ss << timestruct.tm_hour;
ss << timestruct.tm_min;
std::string filingTime = ss.str(); // BAD: '0794'
So, I have a number of questions:
Why is setw() this way?
Are any other manipulators this way?
Is there a difference in behavior between std::ios_base::width() and std::setw()?
Finally is there an online reference that clearly documents this behavior? My vendor documentation (MS Visual Studio 2005) doesn't seem to clearly show this.
Important notes from the comments below:
By Martin:
#Chareles: Then by this requirement all manipulators are sticky. Except setw which seems to be reset after use.
By Charles:
Exactly! and the only reason that setw appears to behave differently is because there are requirements on formatted output operations to explicitly .width(0) the output stream.
The following is the discussion that lead to the above conclusion:
Looking at the code the following manipulators return an object rather than a stream:
setiosflags
resetiosflags
setbase
setfill
setprecision
setw
This is a common technique to apply an operation to only the next object that is applied to the stream. Unfortunately this does not preclude them from being sticky. Tests indicate that all of them except setw are sticky.
setiosflags: Sticky
resetiosflags:Sticky
setbase: Sticky
setfill: Sticky
setprecision: Sticky
All the other manipulators return a stream object. Thus any state information they change must be recorded in the stream object and is thus permanent (until another manipulator changes the state). Thus the following manipulators must be Sticky manipulators.
[no]boolalpha
[no]showbase
[no]showpoint
[no]showpos
[no]skipws
[no]unitbuf
[no]uppercase
dec/ hex/ oct
fixed/ scientific
internal/ left/ right
These manipulators actually perform an operation on the stream itself rather than the stream object (Though technically the stream is part of the stream objects state). But I do not believe they affect any other part of the stream objects state.
ws/ endl/ ends/ flush
The conclusion is that setw seems to be the only manipulator on my version that is not sticky.
For Charles a simple trick to affect only the next item in the chain:
Here is an Example how an object can be used to temporaily change the state then put it back by the use of an object:
#include <iostream>
#include <iomanip>
// Private object constructed by the format object PutSquareBracket
struct SquareBracktAroundNextItem
{
SquareBracktAroundNextItem(std::ostream& str)
:m_str(str)
{}
std::ostream& m_str;
};
// New Format Object
struct PutSquareBracket
{};
// Format object passed to stream.
// All it does is return an object that can maintain state away from the
// stream object (so that it is not STICKY)
SquareBracktAroundNextItem operator<<(std::ostream& str,PutSquareBracket const& data)
{
return SquareBracktAroundNextItem(str);
}
// The Non Sticky formatting.
// Here we temporariy set formating to fixed with a precision of 10.
// After the next value is printed we return the stream to the original state
// Then return the stream for normal processing.
template<typename T>
std::ostream& operator<<(SquareBracktAroundNextItem const& bracket,T const& data)
{
std::ios_base::fmtflags flags = bracket.m_str.flags();
std::streamsize currentPrecision = bracket.m_str.precision();
bracket.m_str << '[' << std::fixed << std::setprecision(10) << data << std::setprecision(currentPrecision) << ']';
bracket.m_str.flags(flags);
return bracket.m_str;
}
int main()
{
std::cout << 5.34 << "\n" // Before
<< PutSquareBracket() << 5.34 << "\n" // Temp change settings.
<< 5.34 << "\n"; // After
}
> ./a.out
5.34
[5.3400000000]
5.34
The reason that width does not appear to be 'sticky' is that certain operations are guaranteed to call .width(0) on an output stream. Those are:
21.3.7.9 [lib.string.io]:
template<class charT, class traits, class Allocator>
basic_ostream<charT, traits>&
operator<<(basic_ostream<charT, traits>& os,
const basic_string<charT,traits,Allocator>& str);
22.2.2.2.2 [lib.facet.num.put.virtuals]: All do_put overloads for the num_put template. These are used by overloads of operator<< taking a basic_ostream and a built in numeric type.
22.2.6.2.2 [lib.locale.money.put.virtuals]: All do_put overloads for the money_put template.
27.6.2.5.4 [lib.ostream.inserters.character]: Overloads of operator<< taking a basic_ostream and one of the char type of the basic_ostream instantiation or char, signed char or unsigned char or pointers to arrays of these char types.
To be honest I'm not sure of the rationale for this, but no other states of an ostream should be reset by formatted output functions. Of course, things like badbit and failbit may be set if there is a failure in the output operation, but that should be expected.
The only reason that I can think of for resetting the width is that it might be surprising if, when trying to output some delimited fields, your delimiters were padded.
E.g.
std::cout << std::setw(6) << 4.5 << '|' << 3.6 << '\n';
" 4.5 | 3.6 \n"
To 'correct' this would take:
std::cout << std::setw(6) << 4.5 << std::setw(0) << '|' << std::setw(6) << 3.6 << std::setw(0) << '\n';
whereas with a resetting width, the desired output can be generated with the shorter:
std::cout << std::setw(6) << 4.5 << '|' << std::setw(6) << 3.6 << '\n';
setw() only affects the next insertion. That's just the way setw() behaves. The behavior of setw() is the same as ios_base::width(). I got my setw() information from cplusplus.com.
You can find a full list of manipulators here. From that link, all the stream flags should stay set until changed by another manipulator. One note about the left, right and internal manipulators: They are like the other flags and do persist until changed. However, they only have an effect when the width of the stream is set, and the width must be set every line. So, for example
cout.width(6);
cout << right << "a" << endl;
cout.width(6);
cout << "b" << endl;
cout.width(6);
cout << "c" << endl;
would give you
> a
> b
> c
but
cout.width(6);
cout << right << "a" << endl;
cout << "b" << endl;
cout << "c" << endl;
would give you
> a
>b
>c
The Input and Output manipulators are not sticky and only occur once where they are used. The parameterized manipulators are each different, here's a brief description of each:
setiosflags lets you manually set flags, a list of which can be found here, so it is sticky.
resetiosflags behaves similar to setiosflags except it unsets the specified flags.
setbase sets the base of integers inserted into the stream (so 17 in base 16 would be "11", and in base 2 would be "10001").
setfill sets the fill character to insert in the stream when setw is used.
setprecision sets the decimal precision to be used when inserting floating point values.
setw makes only the next insertion the specified width by filling with the character specified in setfill
I have:
std::cout << "Start = " << std::dec << (&myObject) << std::endl;
to output an address in decimal. However, the address is still coming out in hex??
(I am outputting one of these for each of ten members, so I don't want to assign each one to a variable and then std::dec the variable separately)
The hex and dec manipulators are for integers, not pointers. Pointers are always rendered in the form that printf's %p formatter would have used on your system (which is, usually, hexadecimal notation).
This helps to emphasise the fact that pointers and numbers are distinct. You may consider it to be one of the rare cases in which number semantics and number representation are, to some degree, coupled.
The best you can do is to cast the pointer to uintptr_t before streaming it:
std::cout << "Start = " << std::dec << uintptr_t(&myObject) << std::endl;
…but please consider whether you really need to do so.
I'm working in C++. I'm given a 10 digit string (char array) that may or may not have 3 dashes in it (making it up to 13 characters). Is there a built in way with the stream to right justify it?
How would I go about printing to the stream right justified? Is there a built in function/way to do this, or do I need to pad 3 spaces into the beginning of the character array?
I'm dealing with ostream to be specific, not sure if that matters.
You need to use std::setw in conjunction with std::right.
#include <iostream>
#include <iomanip>
int main(void)
{
std::cout << std::right << std::setw(13) << "foobar" << std::endl;
return 0;
}
Yes. You can use setw() to set the width. The default justification is right-justified, and the default padding is space, so this will add spaces to the left.
stream << setw(13) << yourString
See: setw(). You'll need to include <iomanip>.
See "setw" and "right" in your favorite C++ (iostream) reference for further details:
cout << setw(13) << right << your_string;
Not a unique answer, but an additional "gotcha" that I discovered and is too long for a comment...
All the formatting stuff is only applied once to yourString. Anything additional, like << yourString2 doesn't abide by the same formatting rules. For instance if I want to right-justify two strings and pad 24 asterisks (easier to see) to the left, this doesn't work:
std::ostringstream oss;
std::string h = "hello ";
std::string t = "there";
oss << std::right << std::setw(24) << h << t;
std::cout << oss.str() << std::endl;
// this outputs
******************hello there
That will apply the correct padding to "hello " only (that's 18 asterisks, making the entire width including the trailing space 24 long), and then "there" gets tacked on at the end, making the end result longer than I wanted. Instead, I wanted
*************hello there
Not sure if there's another way (you could simply redo the formatting I'm sure), but I found it easiest to simply combine the two strings into one:
std::ostringstream oss;
std::string h = "hello ";
std::string t = "there";
// + concatenates t onto h, creating one string
oss << std::right << std::setw(24) << h + t;
std::cout << oss.str() << std::endl;
// this outputs
*************hello there
The whole output is 24 long like I wanted.
Demonstration
printf("%-8s - %s\n", c->name ? c->name : "", c->help);
I think what you're looking for is
cout << left << setw(8) << (c->name ? c->name : "") << " - " << c->help << endl;
The left and setw(8) manipulators together have the same effect as the %-8s formatting specifier in printf. You will need to #include <iomanip> in order for this to work, though, because of the use of setw.
EDIT: As Matthieu M. pointed out, the above will permanently change cout so that any padding operations print out left-aligned. Note that this isn't as bad as it might seem; it only applies when you explicitly use setw to set up some padding. You have a few options for how to deal with this. First, you could just enforce the discipline that before using setw, you always use either the left or right manipulators to left- or right-align the text, respectively. Alternatively, you can use the flags and setf function to capture the current state of the flags in cout:
ios_base::fmtflags currFlags = cout.flags();
cout << left << setw(8) << (c->name ? c->name : "") << " - " << c->help << endl;
cout.setf(currFlags, ios_base::adjustfield);
This works in three steps. The first line reads the current formatting flags from cout, including how it's currently aligning padded output. The second line actually prints out the value. Finally, the last line resets cout's output flags for internal alignment to their old value.
Personally, I think the first option is more attractive, but it's definitely good to know that the second one exists since it's technically more correct.
If you've got the Boost libraries:
std::cout << boost::format("%-8s - %s\n") % (c->name ? c->name : "") % c->help;