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

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

我们有几个练习要在纸上做,我希望在把我的工作交给老师之前能够验证我的答案。我为前几个练习写了一个c++程序,但现在我被困在如何用以下问题验证我的答案:

char a, b;


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


b = a >> 3;

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

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

A = 00111010(它是一个char,所以是1字节)

B = 00001000(它是一个char,所以是1字节)

C = 11111110 11000101(它是短的,所以是2字节)

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

419744 次浏览

这就是你要找的吗?

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

在c++中是否有一种标准的方法来显示内存中数字[…]的二进制表示?

不。没有像std::hexstd::dec那样的std::bin,但自己输出一个二进制数字并不难:

你输出最左边的位,通过屏蔽所有其他的位,左移,并对所有的位重复这一步骤。

(类型中的比特数是sizeof(T) * CHAR_BIT。)

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

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

#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)就可以了。

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

使用动态转换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

下面是获得一个数字的二进制表示的真正方法:

unsigned int i = *(unsigned int*) &x;
#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
}

可重用的功能:

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

这适用于所有的整数。

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

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

在c++ 20中,你可以使用std::format来做到这一点:

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

输出:

11000110

在较旧的系统上,您可以使用{fmt}库std::format是基于。{fmt}还提供了print函数,使这更容易和更有效(godbolt):

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

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