【问题标题】:How can I print 0x0a instead of 0xa using cout?如何使用 cout 打印 0x0a 而不是 0xa?
【发布时间】:2011-08-11 05:48:13
【问题描述】:

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

#include  <iostream>

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

int main()  
{  
    cout << hex << showbase << 10 << endl;  
}

【问题讨论】:

  • 您的具体要求是什么。标题为0x0a,您的问题正文为0x0A。无论哪种方式,明确的 std::cout &lt;&lt; "0x0a"std::cout &lt;&lt; "0x0A" 似乎都可以满足您的要求,但我假设您确实想要格式化数字。您希望(例如)16、255、256、65536、-1 的格式如何?
  • @Charles 问题是关于如何在 x 之后和 A 或 a 之前打印 0。您可以验证第一个答案是错误的,因为它仍然打印 0xa (如果使用大写,则为 0xA)。但无论如何,这个问题已经被标记为已回答。
  • 但是为什么要多出0?你总是想要0x0 还是需要字符串的最小长度?
  • 如果十六进制数是 0xA,我希望它是 0x0A。如果数字是 0x123,我希望它是 0x0123,依此类推,即偶数个十六进制数字。
  • 我认为你不明白我在说什么。您已经明确指定了 10 的显示方式,但是 1 到 9 和 11 到 15 呢? 256呢?你想要0x0a 是因为你想要一个最小宽度还是因为你总是想要一个前导零?除非您完全符合您的规范,否则您可能无法得到您想要的答案。

标签: c++ io iostream iomanip


【解决方案1】:

这在 GCC 中对我有用:

#include  <iostream>
#include  <iomanip>

using namespace std;

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

如果您厌倦了 iostream 的格式怪异,请尝试 Boost.Format。它允许使用老式的 printf 样式的格式说明符,但它是类型安全的。

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

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

更新(2019 年)

查看已被接受的{fmt} library into C++20。基准测试表明它比 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);

【讨论】:

  • 这个答案是错误的。如果有人以前做过cout &lt;&lt; left &lt;&lt; whatever,由于持续的左/右iomanip,你会得到不好的输出。应该是setfill('0') &lt;&lt; setw(2) &lt;&lt; right &lt;&lt; hex 始终保证正确对齐。
  • @fuujuhi ?这是比较苛刻的。我会说它是不完整的。不过,感谢您的建议。
  • @EmileCornier 抱歉,不是故意的。确实,不完整,但不幸的是可能会导致讨厌的错误。由于持久性 iomanip,最近我的代码中有两个错误(完全披露:我曾经用 C++ 编写过很多代码,但现在不再),这让我认为 C++ iostream 是非常错误的。对于现代语言,iostream 使打印最简单的东西成为一场彻头彻尾的噩梦。你以为你打印一个整数,但实际上你用十六进制打印它。或者,您在输出中得到“0x90”,但实际上该值为 0x09。
【解决方案2】:

使用来自iomanipsetwsetfill

#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;
}

就我个人而言,iostream 的有状态特性总是让我很恼火。我认为提升格式是一个更好的选择,所以我推荐了另一个答案。

【讨论】:

  • 我也得到 0xA。为什么要让 iostream 以您想要的方式格式化内容如此困难??
  • 这对我有用:cout &lt;&lt; "0x" &lt;&lt; setfill('0') &lt;&lt; setw(2) &lt;&lt; hex &lt;&lt; 10 &lt;&lt; endl
  • @Doug T.:我冒昧地编辑了您的答案,以便 OP 可以接受它作为有效的答案。
  • @Potatoswatter: setw(2) 似乎与showbase 不匹配,至少在 gcc 4.4.3 中。也许这是 GCC 中的错误?
  • @Charles:对不起,我忘了setiosflags(ios::internal)。这工作:cout &lt;&lt; showbase &lt;&lt; setiosflags(ios::internal) &lt;&lt; setfill('0') &lt;&lt; setw(4) &lt;&lt; hex &lt;&lt; 10 &lt;&lt; endl; 演示:ideone.com/WlusB
【解决方案3】:

如果你想用一种更简单的方式来输出一个十六进制数,你可以写一个这样的函数:

更新版本如下; 0x 基本指示符有两种插入方式,脚注详细说明了它们之间的差异。原始版本保留在答案的底部,以免给正在使用它的任何人带来不便。

请注意,更新版本和原始版本都可能需要针对字节大小为 9 位的倍数的系统进行一些调整。

#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();
}

可以这样使用:

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;

实时查看这两个选项(详见下方脚注):here

脚注:

  1. 此行负责显示基础,可以是以下任意一种:

    << "0x"
    << std::showbase
    
    • 对于尝试将负十六进制数输出为-0x## 而不是&lt;complement of 0x##&gt; 的自定义类型,第一个选项将无法正确显示,符号显示在基数之后(如0x-##)而不是之前。这很少会成为问题,所以我个人更喜欢这个选项。

      如果这是一个问题,那么在使用这些类型时,您可以在输出基数之前检查负性,然后使用abs()(或a custom abs() that returns an unsigned value,如果您需要能够处理最- val 上的 2 补码系统上的负值。

    • val == 0 时,第二个选项将省略基数,显示(例如,对于int,其中int 是32 位)0000000000 而不是预期的0x00000000。这是因为 showbase 标志在内部被视为 printf()# 修饰符。

      如果是这个问题,你可以检查一下是否val == 0,如果是,则进行特殊处理。

  2. 根据选择显示基础的选项,需要更改两行。

    • 如果使用&lt;&lt; "0x",则HEX_BASE_CHARS是不必要的,可以省略。
    • 如果使用&lt;&lt; std::showbase,则提供给setw() 的值需要考虑到这一点:

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

原版如下:

// 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();
}

然后可以这样使用:

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;

工作示例:here

【讨论】:

  • std::internal!你中了大奖!这就是我所缺少的!谢谢@贾斯汀时间。
  • @fljx 不客气。自从发布此答案以来,我已经对其进行了改进,因此我将编辑答案以反映这一点。
  • 所需的包含应该列在某处,据我看:climitsiomanipiostreamtypesstringstringstream,带有@的限制987654357@ 是让我写这篇评论的人。
  • 好主意,@mxmlnkn。更新。 (此外,它在技术上需要ios 而不是iostream,但这没有实际意义,因为无论如何iostream 都需要包含ios。在答案中也注意到了这一点。)
  • 请注意,这可能需要修改以支持 C++20 char8_t,并且让它处理所有字符类型([[un]signed] charcharN_t、@ 987654365@) 为方便起见。在这种情况下,最好在is_char&lt;T&gt; 为真时转换为char_traits&lt;T&gt;::int_type,因为我们已经使用了&lt;string&gt;。 [不过,我目前正在等着看事情进展如何。]
【解决方案4】:

在 C++20 中,您将能够使用 std::format 来执行此操作:

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

输出:

0a

同时你可以使用the {fmt} librarystd::format是基于。 {fmt} 还提供了print 函数,使这更容易和更高效(godbolt):

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

免责声明:我是 {fmt} 和 C++20 std::format 的作者。

【讨论】:

    【解决方案5】:

    答案缺少的重要一点是您必须将right 与上述所有标志一起使用:

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

    【讨论】:

    • 或者,如果你使用std::showbase而不是直接输出0x,你使用std::internal而不是std::right
    【解决方案6】:

    试试这个..您只需根据幅度添加零。

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

    您可以轻松修改它以处理更大的数字。

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

    系数为 16(一位十六进制数):
    16、256、4096、65536、1048576、..
    各自
    0x10, 0x100, 0x1000, 0x10000, 0x100000, ..

    所以你也可以这样写..

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

    等等.. :P

    【讨论】:

      【解决方案7】:

      为了缩短输出十六进制的时间,我做了一个简单的宏

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

      然后

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

      【讨论】:

      • 我笑了。编写 C++ 有时会很麻烦,你不得不求助于诸如宏之类的禁忌领域(“他说宏,他说宏”,“杀了他,杀了他”……为 C++ 重新构想的布莱恩的生活)以保持可读性.
      【解决方案8】:

      使用自动填充“0”或设置将任何数字打印为十六进制。模板允许任何数据类型(例如 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); }
      

      例子:

      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();
      

      输出:

      05,5b,30
      0x0001,0f,ffffffff,0201,0x010003
      

      【讨论】:

        【解决方案9】:
        #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;
        }
        

        【讨论】:

          猜你喜欢
          • 2021-05-20
          • 2014-05-17
          • 1970-01-01
          • 2013-03-31
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多