简体   繁体   中英

c++ insert to a stream with formatting for hex

I often do something like:

uint8_t c=some_value;
std::cout << std::setfill('0') << std::setw(2);
std::cout << std::hex << int(c);
std::cout << std::setfill(' ');

(in particular while dumping debugging information). Wouldn't it be nice to have something manipulatorish that I could put in a stream like this:

std::cout << "c value: 0x" << hexb(c) << '\\n';

that would do all of that? Does anyone know how to do that?

I've gotten this to work but would love to have a simpler way:

#include <iostream>
#include <iomanip>
class hexcdumper{
public:
    hexcdumper(uint8_t c):c(c){};
    std::ostream&
    operator( )(std::ostream& os) const
    {
        // set fill and width and save the previous versions to be restored later
        char fill=os.fill('0');
        std::streamsize ss=os.width(2);

        // save the format flags so we can restore them after setting std::hex
        std::ios::fmtflags ff=os.flags();

        // output the character with hex formatting
        os  << std::hex << int(c);

        // now restore the fill, width and flags
        os.fill(fill);
        os.width(ss);
        os.flags(ff);
        return os;
    }
private:
    uint8_t c;
};

hexcdumper
hexb(uint8_t c)
{
    // dump a hex byte with width 2 and a fill character of '0'
    return(hexcdumper(c));
}

std::ostream& operator<<(std::ostream& os, const hexcdumper& hcd)
{    
   return(hcd(os)); 
}

When I do this:

std::cout << "0x" << hexb(14) << '\n';
  1. hexb(c) is invoked and returns a hexcdumper whose constructor saves c
  2. the overloaded operator<< for hexcdumper invokes hexcdumper::operator() passing it the stream
  3. hexcdumper's operator() does all the magic for us
  4. after hexcdumper::operator() returns, the overloaded operator<< returns the stream as returned from hexcdumper::operator() so chaining works.

On the output, I see:

0x0e

Is there a simpler way to do this?

Patrick

You can do this directly on the stream pipe:

std::cout << "Hex = 0x" << hex << 14 << ", decimal = #" << dec << 14 << endl;

Output:

Hex = 0xe, decimal = #14

Just as a follow up, this does the same this for arbitrary width, and does the same for binary output, for example, assuming the below in in a file called hexbinfmt.h, the following:

#include <hexbinfmt.h>

int
main()
{
    unsigned long long ll=0x7589347dfdf7834;
    std::cout << "hexb(ll): 0x" << hexb(ll) << ", bin(ll): " << bin(ll) << '\n';
    uint8_t u8t=0xce;
    std::cout << "hexb(u8t): 0x" << hexb(u8t) << ", bin(u8t): " << bin(u8t) << '\n';
}

outputs:

hexb(ll): 0x07589347dfdf7834, bin(ll): 0000011101011000100100110100011111011111110111110111100000110100
hexb(u8t): 0xce, bin(u8t): 11001110

Can you help me find a simpler way of doing the same thing?

#ifndef HEXBINFMT_H
#define HEXBINFMT_H
#include <iostream>
#include <iomanip>

template<typename T>
class hexcdumper{
public:
    hexcdumper(T c):c(c){};
    std::ostream&
    operator()(std::ostream& os) const
    {
    // set fill and width and save the previous ones to be restored later
    char fill=os.fill('0');

    std::streamsize ss=os.width(sizeof(T)*2);

    // get a copy of the format flags to be restored after setting std::hex
    std::ios::fmtflags ff=os.flags();

    // put the character out as hex
    if(sizeof(T)==1){
        os << std::hex << int(c);
    }else{
        os << std::hex << c;
    }

    // restore everything
    os.fill(fill);
    os.width(ss);
    os.flags(ff);
    return os;
    }
private:
    T c;
};

template<typename T>
hexcdumper<T>
hexb(T c)
{
    return(hexcdumper<T>(c));
}

template<typename T>
std::ostream& operator<<(std::ostream& os, const hexcdumper<T>& hcd)
{
    return(hcd(os));
}

template<typename T>
class bincdumper{
public:
    bincdumper(T c):c(c){};
    std::ostream&
    operator()(std::ostream& os) const
    {
    T mask=1;
    mask <<= (sizeof(T)*8)-1;

    for(size_t i=0;i<sizeof(T)*8;i++){
        if(c&mask){
        os<<'1';
        }else{
        os<<'0';
        }
        mask>>=1;
    }
    return os;
    }
private:
    T c;
};

template<typename T>
bincdumper<T>
bin(T c)
{
    return(bincdumper<T>(c));
}

template<typename T>
std::ostream& operator<<(std::ostream& os, const bincdumper<T>& bcd)
{
    return(bcd(os));
}
#endif

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM