Reputation: 33046
This question comes from a bug that I got into recently. I was trying to save some integer values to file as hex. As an example, this is what I should do:
cout << std::hex << value << endl; // (1)
But by mistake, I use it as the following:
cout << std::ios::hex << value << endl; // (2)
The compiler does not complain but obviously the result is not correct. I was trying a couple more values randomly and it seems that (2) actually give partially correct result except that it append 800 as a prefix. I don't understand where the 800 is coming from and I don't see a good reference anywhere. Can anybody explain what's happening under the hood?
cout << std::hex << 255 << endl; // output: FF
cout << std::ios::hex << 255 << endl; // output: 800ff
cout << std::hex << 135 << endl; // output: 87
cout << std::ios::hex << 135 << endl; // output: 80087
cout << std::hex << 11 << endl; // output: b
cout << std::ios::hex << 11 << endl; // output: 800b
Upvotes: 18
Views: 3807
Reputation: 153840
std::hex
is a manipulator, i.e., it is a function with a specific signature:
std::ios_base& hex(std::ios_base& stream) {
stream.setf(std::ios_base::hex, std::ios_base::basefield);
return stream;
}
There are some special output operators defined for stream to process manipulators. For the version operating on references to std::ios_base
there is (ignoring that the operator is actually a function template):
std::ostream& operator<< (std::ostream& out, std::ios_base&(*manip)(std::ios_base&));
When used with a stream, the manipulator function is being called and it sets a specific format flag, in this case std::ios_base::hex
(which is how std::ios::hex
is actually defined). Since std::ios_base::hex
is a member of a group of flags (the others are std::ios_base::dec
and std::ios_base::oct
) setting it also needs to clear any potential other flag in the group. Thus, setf()
is called with a mask (std::ios_base::basefield
) to clear any of the other potentially set flags.
The format flags std::ios_base::fmtflags
is a bitmask type. The value std::ios_base::hex
is one of the values. When formatting it you'll get some number, most likely a power of 2 (however, it doesn't have to be a power of 2). The value you see is simply 0x800
(i.e. 2048) printed using hex notation: setting any of the formatting flags (other than the width()
) is sticky, i.e., they remain until the flag is unset. If you want to see the value 2048 (for the implementation you are using) you'd use
std::cout << std::dec << std::ios_base::hex << "\n"; // 2048
std::cout << std::hex << std::ios_base::hex << "\n"; // 800
std::cout << std::showbase << std::ios_base::hex << "\n"; // 0x800
The last line sets the flag showbase
which indicates the base of an integer value with a prefix:
0x
=> hexadecimal0
(but no x
) => octalUpvotes: 11
Reputation: 16824
std::hex
is a special object that, when applied to a stream using operator<<
,
sets the basefield of the stream
str
to hex as if by callingstr.setf(std::ios_base::hex, std::ios_base::base field)
std::ios::hex
(aka std::ios_base::hex
) is the actual bitmask value that gets passed to the setf
method. Its value is implementation defined, and it seems to be 0x800
in your case.
Upvotes: 6
Reputation: 141618
This is actually std::ios_base::hex
. It's an implementation-defined bitmask. Internally, the stream has an integer called fmtflags
where it stores the current state of the formatting.
In your implementation, hex
is the flag 0x800
. Other flags will indicate whether it's in scientific notation mode, whether boolalpha
is on, etc. etc.
The std::hex
function sets the std::ios_base::hex
flag in fmtflags
.
So your output is the integer value of this flag (in hex since you sent std::hex
previously).
Upvotes: 19