如何打印(使用 cout)二进制形式的数字?

How to print (using cout) a number in binary form?

提问人:Jesse Emond 提问时间:9/8/2011 最后编辑:CommunityJesse Emond 更新时间:1/17/2023 访问量:473958

问:

我正在学习一门关于操作系统的大学课程,我们正在学习如何从二进制转换为十六进制,从十进制转换为十六进制等,今天我们刚刚学习了如何使用两者的补码(~数字+1)将有符号/无符号数字存储在内存中。

我们有几个练习要在纸上做,我希望能够在将我的作业提交给老师之前验证我的答案。我为前几个练习编写了一个 C++ 程序,但现在我陷入了如何用以下问题验证我的答案:

char a, b;

short c;
a = -58;
c = -315;

b = a >> 3;

我们需要在内存中显示 和 的二进制表示。abc

我已经在纸上完成了它,它给了我以下结果(所有二进制表示在二的补码之后存储数字):

a = 00111010(它是一个字符,所以 1 个字节)

b = 00001000(它是一个字符,所以 1 个字节)

c = 11111110 11000101(很短,所以 2 个字节)

有没有办法验证我的答案?C++ 中是否有标准方法可以在数字的内存中显示二进制表示,或者我是否必须自己编写每个步骤(计算两者的补码,然后转换为二进制)?我知道后者不会花这么长时间,但我很好奇是否有标准方法可以做到这一点。

C++ 二进制 IOSTREAM 表示 形式 std-bitset

评论

3赞 Nim 9/8/2011
你了解十六进制表示法吗?如果你这样做,你可以打印十六进制表示(使用)操纵器 - 我会把它作为一个练习,让你解决剩下的问题......std::hex
4赞 Mark Ransom 9/8/2011
你非常强调“在记忆中”,但我希望他们不会让你处理字节序问题。
1赞 R. Martinho Fernandes 9/8/2011
你知道什么是字节序吗?如果你这样做了,你关心这个练习吗?这些问题的答案可能会影响问题的答案。
0赞 Kiley Naro 9/8/2011
根据你的 IDE,如果你只是想验证手写解决方案的正确性,而不是实际编写一个程序来显示一些有用的东西,你可以使用 Visual Studio 的内存查看器之类的东西来查看内存的确切内容。
3赞 Konrad Rudolph 9/8/2011
甚至谷歌也这样做,例如“二进制中的-58”——但 +1 表示想要了解如何在代码中自己做到这一点。

答:

-13赞 Kevin 9/8/2011 #1

这是你要找的吗?

std::cout << std::hex << val << std::endl;

评论

35赞 user50049 9/8/2011
主持人备注试图有选择地清除这个答案下的敌对或其他非建设性评论,结果我得到了一个非常破碎的对话。所有评论均被清除。请保持评论的专业性、建设性,最重要的是主题。如果 OP 想要删除它,OP 现在应该已经删除了它。如果您不同意这个答案,请投票。如果可以改进此答案,请编辑。真的,我们是成年人,是吗?我几乎检查了这里所有评论的年龄,以确保每个人都超过 13 岁。</argument>
13赞 sbi 9/8/2011 #2

C++ 中是否有标准方法可以在数字 [...] 的内存中显示二进制表示?

不。没有 、 like 或 ,但自己输出一个数字二进制并不难:std::binstd::hexstd::dec

您可以通过屏蔽所有其他位来输出最左边的位,左移,然后对您拥有的所有位重复此操作。

(类型中的位数为 。sizeof(T) * CHAR_BIT

570赞 Jerry Coffin 9/8/2011 #3

最简单的方法可能是创建一个表示值的 std::bitset,然后将其流式传输到 .cout

#include <bitset>
...

char a = -58;
std::bitset<8> x(a);
std::cout << x << '\n';

short c = -315;
std::bitset<16> y(c);
std::cout << y << '\n';

评论

2赞 Jesse Emond 9/8/2011
请原谅我的无知,但这只会显示一个数字的二进制表示(例如 8 将是 00001000)或它的内存表示(例如,如何通过处理符号位并使用“二的补码”来存储 -8)?
12赞 Potatoswatter 9/8/2011
@Jesse: 的构造函数参数被解释为一个无符号值,其工作原理与 2 的补码相同。严格来说,C++ 不能保证 2 的补码算术,而且您示例中的运算也是未定义的。bitset-58 >> 3
0赞 nirvanaswap 3/16/2016
是否可以将位集值(即本例中的 x 或 y)类型转换为 char*?
1赞 Jerry Coffin 3/16/2016
@nirvanaswap:我想你可以施放它,但结果不太可能有用。如果需要字符串形式的结果,请使用 的成员。bitsetto_string
1赞 nirvanaswap 3/16/2016
谢谢杰瑞,to_string分钟后我发现了。仅供参考,强制转换不起作用,bitset 变量是一些看起来非常神秘的 bitset3ul (?!) 类的对象。最好让抽象来完成工作!
31赞 Cubbi 9/8/2011 #4

如果要显示任何对象的位表示形式,而不仅仅是整数,请记住先重新解释为 char 数组,然后您可以将该数组的内容打印为十六进制,甚至二进制(通过位集):

#include <iostream>
#include <bitset>
#include <climits>

template<typename T>
void show_binrep(const T& a)
{
    const char* beg = reinterpret_cast<const char*>(&a);
    const char* end = beg + sizeof(a);
    while(beg != end)
        std::cout << std::bitset<CHAR_BIT>(*beg++) << ' ';
    std::cout << '\n';
}
int main()
{
    char a, b;
    short c;
    a = -58;
    c = -315;
    b = a >> 3;
    show_binrep(a);
    show_binrep(b);
    show_binrep(c);
    float f = 3.14;
    show_binrep(f);
}

请注意,大多数常见的系统都是 little-endian,因此输出不是您期望的1111111 011000101,因为这不是它在内存中的存储方式。如果您正在寻找二进制中的表示,那么一个简单的方法就可以了。show_binrep(c)cout << bitset<16>(c)

5赞 eudoxos 9/8/2011 #5

与已经发布的内容类似,只需使用位移和掩码来获取位;可用于任何类型,作为一个模板(只是不确定是否有标准方法可以在 1 个字节中获取位数,我在这里使用了 8 个)。

#include<iostream>
#include <climits>

template<typename T>
void printBin(const T& t){
    size_t nBytes=sizeof(T);
    char* rawPtr((char*)(&t));
    for(size_t byte=0; byte<nBytes; byte++){
        for(size_t bit=0; bit<CHAR_BIT; bit++){
            std::cout<<(((rawPtr[byte])>>bit)&1);
        }
    }
    std::cout<<std::endl;
};

int main(void){
    for(int i=0; i<50; i++){
        std::cout<<i<<": ";
        printBin(i);
    }
}

评论

5赞 R. Martinho Fernandes 9/8/2011
获取每字节位数的标准方法是宏。CHAR_BIT
0赞 gsamaras 10/31/2018
根据 @R.MartinhoFernandes 的评论,sbi 似乎编辑了 Εύδοξος 的帖子。但是,他没有改变最后一句话。我会编辑。
161赞 r233967 3/17/2013 #6

使用动态转换为 。没有临时变量,没有循环,没有函数,没有宏。std::bitset

Live On Coliru(科里鲁生活公寓)

#include <iostream>
#include <bitset>

int main() {
    int a = -58, b = a>>3, c = -315;

    std::cout << "a = " << std::bitset<8>(a)  << std::endl;
    std::cout << "b = " << std::bitset<8>(b)  << std::endl;
    std::cout << "c = " << std::bitset<16>(c) << std::endl;
}

指纹:

a = 11000110
b = 11111000
c = 1111111011000101

评论

31赞 Apollys supports Monica 3/15/2019
请注意,硬编码大小不是必需的。例如,打印使用:.xstd::cout << std::bitset<8*sizeof(x)>(x)
-5赞 user5463518 10/19/2015 #7

这是获得数字的二进制表示的真正方法:

unsigned int i = *(unsigned int*) &x;

评论

1赞 adentinger 9/2/2018
不;这只是将 x 复制到 i 中。除非你是开玩笑的?
0赞 WriteYour NameHere 11/5/2015 #8
#include <iostream> 
#include <cmath>       // in order to use pow() function
using namespace std; 

string show_binary(unsigned int u, int num_of_bits);

int main() 
{ 

  cout << show_binary(128, 8) << endl;   // should print 10000000
  cout << show_binary(128, 5) << endl;   // should print 00000
  cout << show_binary(128, 10) << endl;  // should print 0010000000

  return 0; 
}

string show_binary(unsigned int u, int num_of_bits) 
{ 
  string a = "";

  int t = pow(2, num_of_bits);   // t is the max number that can be represented

  for(t; t>0; t = t/2)           // t iterates through powers of 2
      if(u >= t){                // check if u can be represented by current value of t
          u -= t;
          a += "1";               // if so, add a 1
      }
      else {
          a += "0";               // if not, add a 0
      }

  return a ;                     // returns string
}

评论

0赞 BmyGuest 4/6/2018
不应该是吗?int t = pow(2, num_of_bits - 1);
4赞 Shital Shah 6/4/2018 #9

可重用功能:

template<typename T>
static std::string toBinaryString(const T& x)
{
    std::stringstream ss;
    ss << std::bitset<sizeof(T) * 8>(x);
    return ss.str();
}

用法:

int main(){
  uint16_t x=8;
  std::cout << toBinaryString(x);
}

这适用于所有类型的整数。

0赞 Ratah 4/15/2019 #10

使用旧的 C++ 版本,您可以使用以下代码片段:

template<typename T>
string toBinary(const T& t)
{
  string s = "";
  int n = sizeof(T)*8;
  for(int i=n-1; i>=0; i--)
  {
    s += (t & (1 << i))?"1":"0";
  }
  return s;
}

int main()
{
  char a, b;

  short c;
  a = -58;
  c = -315;

  b = a >> 3;

  cout << "a = " << a << " => " << toBinary(a) << endl;
  cout << "b = " << b << " => " << toBinary(b) << endl;
  cout << "c = " << c << " => " << toBinary(c) << endl;
}

a = => 11000110
b = => 11111000
c = -315 => 1111111011000101

评论

0赞 David Ledger 10/16/2019
打印错误的位数。111 000 110 是 9 位,而不是 8 位。
0赞 Ratah 10/29/2019
我犯了边界错误,请立即检查
2赞 user5673656 5/2/2020 #11

使用 std::bitset 答案和便捷模板:

#include <iostream>
#include <bitset>
#include <climits>

template<typename T>
struct BinaryForm {
    BinaryForm(const T& v) : _bs(v) {}
    const std::bitset<sizeof(T)*CHAR_BIT> _bs;
};

template<typename T>
inline std::ostream& operator<<(std::ostream& os, const BinaryForm<T>& bf) {
    return os << bf._bs;
}

像这样使用它:

auto c = 'A';
std::cout << "c: " << c << " binary: " << BinaryForm{c} << std::endl;
unsigned x = 1234;
std::cout << "x: " << x << " binary: " << BinaryForm{x} << std::endl;
int64_t z { -1024 };
std::cout << "z: " << z << " binary: " << BinaryForm{z} << std::endl;

生成输出:

c: A binary: 01000001
x: 1234 binary: 00000000000000000000010011010010
z: -1024 binary: 1111111111111111111111111111111111111111111111111111110000000000
69赞 vitaut 12/17/2020 #12

在 C++20 中,您可以使用 std::format 来执行此操作:

unsigned char a = -58;
std::cout << std::format("{:b}", a);

输出:

11000110

在较旧的系统上,您可以使用 {fmt} 库,是基于。{fmt} 还提供了使此操作更加简单和高效的功能 (godbolt):std::formatprint

unsigned char a = -58;
fmt::print("{:b}", a);

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

评论

0赞 rturrado 4/10/2021
std::format在 Visual Studio 2019 中尚不可用,是吗?
3赞 Chris G. 2/7/2022
@rturrado在 Visual Studio 2019 中可用。您必须设置 .std::format#include <format>/std:c++latest
0赞 Richy 12/9/2022 #13

我在网上玩竞技编码游戏时遇到了这个问题。这是一个快速实施且相当直观的解决方案。它还避免输出前导零或依赖<bitset>

std::string s;
do {
    s = std::to_string(r & 1) + s;
} while ( r>>=1 );

std::cout << s;

但是,您应该注意,此解决方案将增加您的运行时间,因此,如果您正在竞争优化或根本不竞争,则应使用此页面上的其他解决方案之一。

评论

0赞 startup.maker 10/15/2023
这就是我正在寻找的确切解决方案“以二进制打印,同时避免输出前导零”