如何使用 cout 打印0x0a 而不是0xa?

我如何打印0x0a,而不是0xa 使用 cout?

#include  <iostream>


using std::cout;
using std::endl;
using std::hex;


int main()
{
cout << hex << showbase << 10 << endl;
}
79079 次浏览

Use setw and setfill from iomanip

#include  <iostream>
#include  <iomanip>


using std::cout;
using std::endl;
using std::hex;


int main()
{
cout << "0x" << std::setfill('0') << std::setw(2) << hex << 10 << endl;
}

Personally, the stateful nature of iostreams always annoys me. I think boost format is a better option, so I'd recommended the other answer.

This works for me in GCC:

#include  <iostream>
#include  <iomanip>


using namespace std;


int main()
{
cout << "0x" << setfill('0') << setw(2) << right << hex << 10 << endl;
}

If you are getting sick and tired of iostream's formatting quirkiness, give Boost.Format a try. It allows good-old-fashioned, printf-style format specifiers, yet it is type-safe.

#include <iostream>
#include <boost/format.hpp>


int main()
{
std::cout << boost::format("0x%02x\n") % 10;
}

UPDATE (2019)

Check out the {fmt} library that's been accepted into C++20. Benchmarks show it to be faster than Boost.Format.

#if __has_include(<format>)
#include <format>
using std::format;
#else
#include <fmt/format.h>
using fmt::format;
#endif


std::cout << format("{:#04x}\n", 10);

try this.. you simply prepend zeroes based on magnitude.

cout << hex << "0x" << ((c<16)?"0":"") << (static_cast<unsigned int>(c) & 0xFF) << "h" << endl;

You can easily modify this to work with larger numbers.

cout << hex << "0x";
cout << ((c<16)?"0":"") << ((c<256)?"0":"");
cout << (static_cast<unsigned int>(c) & 0xFFF) << "h" << endl;

Factor is 16 (for one hex-digit):
16, 256, 4096, 65536, 1048576, ..
respective
0x10, 0x100, 0x1000, 0x10000, 0x100000, ..

Therefore you could also write like this..

cout << hex << "0x" << ((c<0x10)?"0":"") << ((c<0x100)?"0":"") << ((c<0x1000)?"0":"") << (static_cast<unsigned int>(c) & 0xFFFF) << "h" << endl;

And so on.. :P

The important thing that the answer is missing is that you must use right with all of the above mentioned flags:

cout<<"0x"<<hex<<setfill('0')<<setw(2)<<right<<10;

If you want to make an easier way to output a hex number, you could write a function like this:

Updated version is presented below; there are two ways the 0x base indicator can be inserted, with footnotes detailing the differences between them. The original version is preserved at the bottom of the answer, so as not to inconvenience anyone that was using it.

Note that both the updated and original versions may need some tailoring for systems where the byte size is a multiple of 9 bits.

#include <type_traits> // For integral_constant, is_same.
#include <string>      // For string.
#include <sstream>     // For stringstream.
#include <ios>         // For hex, internal, [optional] showbase.
// Note: <ios> is unnecessary if <iostream> is also included.
#include <iomanip>     // For setfill, setw.
#include <climits>     // For CHAR_BIT.


namespace detail {
constexpr int HEX_DIGIT_BITS = 4;
//constexpr int HEX_BASE_CHARS = 2; // Optional.  See footnote #2.


// Replaced CharCheck with a much simpler trait.
template<typename T> struct is_char
: std::integral_constant<bool,
std::is_same<T, char>::value ||
std::is_same<T, signed char>::value ||
std::is_same<T, unsigned char>::value> {};
}


template<typename T>
std::string hex_out_s(T val) {
using namespace detail;


std::stringstream sformatter;
sformatter << std::hex
<< std::internal
<< "0x"                                             // See footnote #1.
<< std::setfill('0')
<< std::setw(sizeof(T) * CHAR_BIT / HEX_DIGIT_BITS) // See footnote #2.
<< (is_char<T>::value ? static_cast<int>(val) : val);


return sformatter.str();
}

It can be used as follows:

uint32_t       hexU32 = 0x0f;
int            hexI   = 0x3c;
unsigned short hexUS  = 0x12;


std::cout << "uint32_t:       " << hex_out_s(hexU32) << '\n'
<< "int:            " << hex_out_s(hexI)   << '\n'
<< "unsigned short: " << hex_out_s(hexUS)  << std::endl;

See both options (as detailed in footnotes, below) live: here.

Footnotes:

  1. This line is responsible for showing the base, and can be either of the following:

    << "0x"
    << std::showbase
    
    • The first option will display improperly for custom types that try to output negative hex numbers as -0x## instead of as <complement of 0x##>, with the sign displaying after the base (as 0x-##) instead of before it. This is very rarely an issue, so I personally prefer this option.

      If this is an issue, then when using these types, you can check for negativity before outputting the base, then using abs() (or a custom abs() that returns an unsigned value, if you need to be able to handle the most-negative values on a 2's complement system) on val.

    • The second option will omit the base when val == 0, displaying (e.g., for int, where int is 32 bits) 0000000000 instead of the expected 0x00000000. This is due to the showbase flag being treated like printf()'s # modifier internally.

      If this is an issue, you can check whether val == 0, and apply special handling when it does.

  2. Depending on which option was chosen for showing the base, two lines will need to be changed.

    • If using << "0x", then HEX_BASE_CHARS is unnecessary, and can be omitted.
    • If using << std::showbase, then the value supplied to setw() needs to account for this:

      << std::setw((sizeof(T) * CHAR_BIT / HEX_DIGIT_BITS) + HEX_BASE_CHARS)
      

The original version is as follows:

// Helper structs and constants for hex_out_s().
namespace hex_out_helper {
constexpr int HEX_DIGIT_BITS = 4; // One hex digit = 4 bits.
constexpr int HEX_BASE_CHARS = 2; // For the "0x".


template<typename T> struct CharCheck {
using type = T;
};


template<> struct CharCheck<signed char> {
using type = char;
};


template<> struct CharCheck<unsigned char> {
using type = char;
};


template<typename T> using CharChecker = typename CharCheck<T>::type;
} // namespace hex_out_helper




template<typename T> std::string hex_out_s(T val) {
using namespace hex_out_helper;


std::stringstream sformatter;
sformatter << std::hex
<< std::internal
<< std::showbase
<< std::setfill('0')
<< std::setw((sizeof(T) * CHAR_BIT / HEX_DIGIT_BITS) + HEX_BASE_CHARS)
<< (std::is_same<CharChecker<T>, char>{} ? static_cast<int>(val) : val);
return sformatter.str();
}

Which can then be used like this:

uint32_t       hexU32 = 0x0f;
int            hexI   = 0x3c;
unsigned short hexUS  = 0x12;


std::cout << hex_out_s(hexU32) << std::endl;
std::cout << hex_out_s(hexI) << std::endl;
std::cout << "And let's not forget " << hex_out_s(hexUS) << std::endl;

Working example: here.

To shorten things up for outputting hex, I made a simple macro

#define PADHEX(width, val) setfill('0') << setw(width) << std::hex << (unsigned)val

then

cout << "0x" << PADHEX(2, num) << endl;

Print any number to hex with auto-padding '0' or set. Template allows any data type (e.g. uint8_t)

template<typename T, typename baseT=uint32_t> struct tohex_t {
T num_;
uint32_t width_;
bool showbase_;


tohex_t(T num, bool showbase = false, uint32_t width = 0) { num_ = num; showbase_ = showbase; width_ = width; }
friend std::ostream& operator<< (std::ostream& stream, const tohex_t& num) {
uint32_t w;
baseT val;


if (num.showbase_)
stream << "0x";


if (num.width_ == 0) {
w = 0;
val = static_cast<baseT>(num.num_);
do { w += 2; val = val >> 8; } while (val > 0);
}
else {
w = num.width_;
}
stream << std::hex << std::setfill('0') << std::setw(w) << static_cast<baseT>(num.num_);


return stream;
}
};
template<typename T> tohex_t<T> TO_HEX(T const &num, bool showbase = false, uint32_t width = 0) { return tohex_t<T>(num, showbase, width); }

Example:

std::stringstream sstr;
uint8_t ch = 91;
sstr << TO_HEX(5) << ',' << TO_HEX(ch) << ',' << TO_HEX('0') << std::endl;
sstr << TO_HEX(1, true, 4) << ',' << TO_HEX(15) << ',' << TO_HEX(-1) << ',';
sstr << TO_HEX(513) << ',' << TO_HEX((1 << 16) + 3, true);
std::cout << sstr.str();

Output:

05,5b,30
0x0001,0f,ffffffff,0201,0x010003
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
/*This should print out 0x0a. The internal adjustment pads the width with the fill character*/
cout << hex << showbase << internal << setfill('0') << setw(4) << 10 << endl;
}

In C++20 you'll be able to use std::format to do this:

std::cout << std::format("{:02x}\n", 10);

Output:

0a

In the meantime you can use the {fmt} library, std::format is based on. {fmt} also provides the print function that makes this even easier and more efficient (godbolt):

fmt::print("{:02x}\n", 10);

Disclaimer: I'm the author of {fmt} and C++20 std::format.