Reputation: 11130
There are many questions regarding how to pad a fixed number of leading zeroes when using C++ streams with variables we want represented in hexadecimal format:
std::cout << std::hex << setfill('0') << setw(8) << myByteSizedVar;
My question regards how to do this for not a fixed width, but a multiple of some fixed amount - likely 8 for the obvious reason that when comparing outputs we might want:
0x87b003a
0xab07
To match up for width to be compared more easily (okay the top is larger - but try a bitwise comparison in your head? Easily confused.)
0x87b003a
0x000ab07
Nice, two bytes lined up nice and neatly. Except we only see 7 bits - which is not immediately obvious (especially if it were 15/16, 31/32, etc.), possibly causing us to mistake the top for a negative number (assuming signed).
All well and good, we can set the width to 8 as above.
However, when making the comparison next to say a 32-bit word:
0x000000000000000000000000087b003a
0x238bfa700af26fa930b00b130b3b022b
It may be more unneccessary, depending on the use, or even misleading if dealing with hardware where the top number actually has no context in which to be a 32-bit word.
What I would like, is to automagically set the width of the number to be a multiple of 8, like:
std::cout << std::hex << std::setfill('0') << setWidthMultiple(8) << myVar;
For results like:
0x00000000
0x388b7f62
0x0000000f388b7f62
How is this possible with standard libraries, or a minimal amount of code? Without something like Boost.Format
.
Upvotes: 3
Views: 1787
Reputation: 153909
There's no immediate support for it, because it involves more
than one input value (if I understand what you're asking for
correctly). The only solution which comes to mind is to use
std::max
to find the largest value, and then derive the number
of digits you need from that, say by using a table:
struct DigitCount
{
unsigned long long maxValue;
int digits;
};
static const DigitCount digitCount[] =
{
{ 255UL, 2 },
{ 65535UL, 4 },
{ 16777215UL, 6 },
{ 4294967295UL, 8 },
};
and looking up the width in it.
Upvotes: 0
Reputation: 476970
How about this:
template <typename Int>
struct Padme
{
static_assert(std::is_unsigned<Int>::value, "Unsigned ints only");
Int n_;
explicit Padme(Int n) : n_(n) {}
template <typename Char, typename CTraits>
friend
std::basic_ostream<Char, CTraits> & operator<<(
std::basic_ostream<Char, CTraits> & os, Padme p)
{
return os << std::setw(ComputeWidth(p.n_)) << p.n_;
}
static std::size_t ComputeWidth(Int n)
{
if (n < 0x10000) { return 4; }
if (n < 0x100000000) { return 8; }
if (n < 0x1000000000000) { return 12; }
return 16;
}
};
template <typename Int>
Padme<Int> pad(Int n) { return Padme<Int>(n); }
Usage:
std::cout << pad(129u) << "\n";
With some more work you could provide versions with different digit group sizes, different number bases etc. And for signed types you could stick std::make_unsigned
into the pad
function template.
Upvotes: 4