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


215

我正在上一本关于操作系统的大学课程,我们正在学习如何从二进制转换为十六进制,从十进制转换为十六进制,等等。今天,我们刚刚学习了如何使用二进制补码(〜number)将有符号/无符号数字存储在内存中。 +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 ++中是否有一种标准的方法可以显示数字在内存中的二进制表示形式,还是我必须自己对每个步骤进行编码(计算二者的补码,然后转换为二进制)?我知道后者不会花很长时间,但是我很好奇是否有标准的方法可以这样做。


2
您了解十六进制表示法吗?如果您愿意,可以打印十六进制表示法(使用std::hex)操纵器-我将其作为练习来解决其余问题……
Nim

3
您经常强调“记忆中”,但我希望他们不会让您处理字节序问题。
Mark Ransom

您知道什么是字节序吗?如果这样做,您是否对此练习感兴趣?这些问题的答案可能会影响您问题的答案。
R. Martinho Fernandes

根据您的IDE,如果您只是想验证手写解决方案的正确性,而不是实际编写程序来显示有用的内容,则可以使用Visual Studio的内存查看器之类的内容来查看内存的确切内容。
Kiley Naro

1
甚至Google都这样做,例如“ -58 in binary”,但是+1表示希望自己找到如何在代码中进行操作。
康拉德·鲁道夫

Answers:


419

最简单的方法可能是创建一个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';

23
啊,我一直忘了std::bitset+1从我。
2011年

2
对不起,请问这将仅显示数字的二进制表示形式(例如8将是00001000)还是其内存表示形式(例如,如何通过照顾符号位并使用“二进制补码”来存储-8)?
杰西·埃蒙德

12
@Jesse:bitset的构造方法参数被解释为无符号值,其结果与二进制补码相同。严格来说,C ++不保证二进制补码运算,并且-58 >> 3示例中的操作也是未定义的。
Potatoswatter 2011年

我可以将位集值(在此示例中为x或y)转换为char *吗?
nirvanaswap '16

1
谢谢杰里,我在几分钟后发现了to_string。仅供参考,强制转换不起作用,bitset变量是某些看起来很神秘的bitset3ul(?!)类的对象。最好让抽象完成工作!
nirvanaswap '16

102

即时转换为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

6
请注意,不需要硬编码大小。例如打印x使用:std::cout << std::bitset<8*sizeof(x)>(x)
Apollys

25

如果要显示任何对象的位表示形式,而不仅仅是整数,请记住首先将其重新解释为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);
}

需要注意的是最常见的系统是小端,这样的输出show_binrep(c)没有的1111111 011000101你期望的,因为这不是它是如何存储在内存中。如果您正在寻找二进制形式的表示形式,那么一个简单的方法就cout << bitset<16>(c)可以了。


11

在C ++中,有没有一种标准的方法可以在内存中显示二进制表示形式?

std::bin,没有,std::hexstd::dec,但您自己输出数字二进制并不难:

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

(一种类型中的位数是sizeof(T) * CHAR_BIT。)


7

类似于已经发布的内容,只是使用位移和掩码来获取位;可用于任何类型的模板(仅不确定是否有一种标准方法来获取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);
    }
}

3
获取每个字节的位数的标准方法是宏CHAR_BIT
R. Martinho Fernandes

似乎sbi根据@ R.MartinhoFernandes的评论编辑了Εύδοξος的帖子。但是,他没有更改最后一句话。我会编辑。
gsamaras

3

可重用功能:

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

这适用于所有整数。


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

不应该int t = pow(2, num_of_bits - 1);吗?
BmyGuest

0

使用旧的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

打印错误的位数。111 000 110是9个比特,而不是8
大卫总帐

我犯了边界错误,请立即检查
Ratah,

0

使用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: " <<  << " binary: " << BinaryForm{z} << std::endl;

产生输出:

c: A binary: 01000001
x: 1234 binary: 00000000000000000000010011010010
z: -1024 binary: 1111111111111111111111111111111111111111111111111111110000000000

-5

这是获取数字的二进制表示形式的真实方法:

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

没有 这只是将x复制到i中。除非您是在开玩笑?
AnthonyD973 '18

-11

这是您要找的东西吗?

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

30
主持人请注意,试图在此答案下有​​选择地清除反对性或其他非建设性的评论,但最终导致了一段非常破裂的对话。所有评论均被清除。请保持评论的专业性,建设性,最重要的是关于主题。如果OP想要删除它,那么OP会立即删除它。如果您不同意此答案,请投票。如果您可以改善此答案,请进行编辑。</argument>。真的,我们是成年人,是吗?我几乎检查了所有的评论这里的年龄,以确保每个人都在13
蒂姆后
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.