This question arose from a discussion I was having about the correct way to output a numeric value using the usual ostream & operator << (ostream &, some_type)
for a numeric type in C++.
The way I'm familiar with the behavior of std::showbase and std::showpos in each base, they are basically mutually exclusive. That is: in decimal no base is shown, and the '+' is added on positive numbers; whereas in hexadecimal or octal, the base is shown, but a '+' is not shown (nor is a minus), as the value of the type is printed as if it's cast to an unsigned type.
For example, this simple (verbose) program:
#include <iostream>
int main() {
std::cout << std::dec << std::showpos << std::showbase << int64_t(+5) << std::endl;
std::cout << std::oct << std::showpos << std::showbase << int64_t(+5) << std::endl;
std::cout << std::hex << std::showpos << std::showbase << int64_t(+5) << std::endl;
std::cout << std::dec << std::showpos << std::showbase << int64_t(-5) << std::endl;
std::cout << std::oct << std::showpos << std::showbase << int64_t(-5) << std::endl;
std::cout << std::hex << std::showpos << std::showbase << int64_t(-5) << std::endl;
}
Gives this output when compiled with GCC:
+5
05
0x5
-5
01777777777777777777773
0xfffffffffffffffb
This is what I've always expected, having used C++ for many years, but is this really guaranteed by the standard, or is this just common behavior? For example, could a standard-compliant C++ compiler output one of these sequences instead?
+5
+05
+0x5
-5
01777777777777777777773
0xfffffffffffffffb
or even:
+5
+05
+0x5
-5
-05
-0x5
For ios_base
itself, no. showpos
and showbase
calls the single-argument setf
(§27.5.6.1[fmtflags.manip]/5 and /13) on the stream, which the two does not affect each other.
Going deeper, a std::ostream
uses the locale::facet::put
function to print an integer (§27.7.3.6.2[ostream.inserters.arithmetic]/1), and its implementation locale::facet::do_put
(§22.4.2.2.2[facet.num.put.virtuals]/5) specifies:
All tables used in describing stage 1 are ordered. That is, the first line whose condition is true applies. A line without a condition is the default behavior when none of the earlier lines apply.
...
The conversion specifier has the following optional additional qualifiers prepended as indicated in Table 90.
Table 90 — Numeric conversions +-----------------------+-------------------+------------------+ | Type(s) | State | stdio equivalent | +=======================+===================+==================+ | | flags & showpos | + | | an integral type | | | | | flags & showbase | # | +-----------------------+-------------------+------------------+ | | flags & showpos | + | | a floating-point type | | | | | flags & showpoint | # | +-----------------------+-------------------+------------------+...
The representations at the end of stage 1 consists of the char’s that would be printed by a call of
printf(s, val)
wheres
is the conversion specifier determined above.
Here, we see that showpos
and showbase
are in the same cell, which, I believe the standard implicitly mean that they're in the same "line", and thus both applies (it can be seen from std::cout << std::showpos << std::showpoint << 6.0
for the following "line"), and the two flags are still not mutually exclusive here.
So far, we see that showpos
and showbase
are not exclusive in C++, and the actual formatting behavior is defined by printf
(though the implementation doesn't need to use printf
, e.g. libc++ uses sprintf
, while libstdc++ does not), which we have to check the C standard.
In C, using +
(showpos
) with o
and x
/X
(oct
and hex
) is not defined, because C99 §7.19.6.1/6 and /8 says
+
The result of a signed conversion always begins with a plus or minus sign. ...
o
,u
,x
,X
The
unsigned int
argument is converted to ...
The argument is not signed, so the +
cannot apply. The behavior is not written out, so it is undefined.
Adding #
(showbase
) to d
(dec
) is also undefined behavior, as clause /6 says:
#
The result is converted to an “alternative form”. For
o
conversion, ... Forx
(orX
) conversion, ... Fora
,A
,e
,E
,f
,F
,g
, andG
conversions, ... Forg
andG
conversions, ... For other conversions, the behavior is undefined.
Oops.
Therefore, not only the two flags are not mutually exclusive, the output is not defined at all. Scenarios 2 and 3 OP mentioned may happen. In gcc and clang, the conflicting option (showpos
for oct
and hex
; showbase
for dec
) are simply ignored, which gives one an illusion of the two options being mutually exclusive, but the standard will not guarentee that.
(Disclaimer: I am using n3242 and n1124 as reference, the final standard might not be exactly the same)
Bit of googling found me this page which says the following on the subject:
Note that negative integers are not printed as such in octal or hexadecimal. Rather, the internal bit patterns are interpreted as always being positive values.
If this is accurate, it would make sense that showpos
would do nothing, why show a +
in front of a number that is always positive?
来源:https://stackoverflow.com/questions/8424260/are-stdshowbase-and-stdshowpos-mutually-exclusive