【问题标题】:Printing zero-padded hex with std::cout [duplicate]使用 std::cout 打印零填充十六进制 [重复]
【发布时间】:2014-02-20 09:22:55
【问题描述】:

假设我有一个 dword,我想用 std::cout 和左填充零输出十六进制,所以 0xabcd 将显示为 0x0000abcd。看来您必须这样做:

uint32_t my_int = 0xabcd;

std::cout << "0x" << std::hex << std::setw(8) << std::setfill('0')
    << my_int << std::endl;

这对于可以在 C 中使用 printf("0x%08X\n", my_int); 完成的事情来说似乎很荒谬。有什么办法可以缩短这个时间,同时仍然使用 std::cout 进行输出(除了使用命名空间 std)?

【问题讨论】:

  • 编写一个函数以格式化十六进制输出并调用它。
  • 较短是相对的,我想。如果您认为 printf() 背后的代码很短,我可以向您保证,它绝不是。您只需要自己滚动(看起来与您在这里的相似)。你总是可以编写一个操纵器类/运算符对,允许类似std::cout &lt;&lt; as_hex(n,8,0);
  • 为了让它更短,我会使用宏来隐藏丑陋,例如#define PAD_HEX(digits) std::hex &lt;&lt; std::setw(digits) &lt;&lt; std::setfill('0') 然后在后面的代码中将其用作std::cout &lt;&lt; "0x" &lt;&lt; PAD_HEX(8) &lt;&lt; my_int ..

标签: c++ printf iostream cout


【解决方案1】:

我想你可以写一个“流操纵器”。如果您有多个要以这种格式打印的十六进制数字,这很有用。这显然不是一个理想的解决方案,但是使用包装器类型,您可以制作自己的“格式标志”来切换它。请参阅Sticky custom stream manipulator 了解更多信息。

#include <iostream>
#include <iomanip>

static int const index = std::ios_base::xalloc();

std::ostream& hexify(std::ostream& stream) {
    stream.iword(index) = 1;
    return stream;
}

std::ostream& nohexify(std::ostream& stream) {
    stream.iword(index) = 0;
    return stream;
}

struct WrapperType {
    uint32_t _m;
public:
    WrapperType(uint32_t m) : _m(m)
    {
    }

    uint32_t getm() const
    {
        return _m;
    }
};
std::ostream& operator<< (std::ostream& os, const WrapperType& t) {
    if (os.iword(index))
        return os << "0x" << std::hex << std::setw(8) << std::setfill('0') << t.getm();
    else
        return os << t.getm();
}

int main()
{
    WrapperType my_int{0xabcd};
    std::cout << hexify << my_int << my_int;
    std::cout << nohexify << my_int;
}

【讨论】:

  • +1 完全是我这样做的方式,但是宽度操纵器在每次发布到流operator &lt;&lt; 时都会重置(我记得),所以你可能必须使它成为参数化的一部分机械手。我可能错了,但他们似乎就是这样工作的(或者恰恰相反,我有一个阅读障碍的时刻)。编辑:刚刚测试过,你是完全正确的。我有阅读障碍。很抱歉造成混乱。
  • @WhozCraig 我编辑了我的答案,但我不确定它是否更好。我的意思是必须记住使用WrapperType 进行格式化可能会很烦人,这是您仅使用函数的解决方案更好的地方。但是如果 OP 是懒惰的,也许这会节省打字。
【解决方案2】:

我不会改变流的(全局)标志,只是一个操纵器:

#include <iostream>
#include <iomanip>
#include <limits>

template <typename T>
struct Hex
{
    // C++11:
    // static constexpr int Width = (std::numeric_limits<T>::digits + 1) / 4;
    // Otherwise:
    enum { Width = (std::numeric_limits<T>::digits + 1) / 4 };
    const T& value;
    const int width;

    Hex(const T& value, int width = Width)
    : value(value), width(width)
    {}

    void write(std::ostream& stream) const {
        if(std::numeric_limits<T>::radix != 2) stream << value;
        else {
            std::ios_base::fmtflags flags = stream.setf(
                std::ios_base::hex, std::ios_base::basefield);
            char fill = stream.fill('0');
            stream << "0x" << std::setw(width) << value;
            stream.fill(fill);
            stream.setf(flags, std::ios_base::basefield);
        }
    }
};

template <typename T>
inline Hex<T> hex(const T& value, int width = Hex<T>::Width) {
    return Hex<T>(value, width);
}

template <typename T>
inline std::ostream& operator << (std::ostream& stream, const Hex<T>& value) {
    value.write(stream);
    return stream;
}

int main() {
    std::uint8_t u8 = 1;
    std::uint16_t u16 = 1;
    std::uint32_t u32 = 1;
    std::cout << hex(unsigned(u8), 2) << ", " << hex(u16) << ", " << hex(u32) << '\n';
}

【讨论】:

  • 我更喜欢这种方法。我不确定数学是如何比较的,但我也更喜欢将默认宽度计算为:(sizeof(T) * 2)(每字节 2 个十六进制字符)。这对我来说似乎更简单。
【解决方案3】:

我的 C++ 生锈了,但如何使用 Boost 格式:http://www.boost.org/doc/libs/1_37_0/libs/format/index.html

【讨论】:

  • 这将有套件更好地作为评论。
猜你喜欢
  • 2013-03-31
  • 1970-01-01
  • 2020-05-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-14
  • 2012-09-20
相关资源
最近更新 更多