Как напечатать (используя cout) способ хранения числа в памяти?
Я учусь в колледже на курсах по операционным системам, и мы учимся, как преобразовывать двоичные числа в шестнадцатеричные, десятичные в шестнадцатеричные и т. Д., И сегодня мы только что узнали, как числа со знаком / без знака хранятся в памяти с помощью дополнения к двум (~ число + 1)
У нас есть пара упражнений на бумаге, и я хотел бы иметь возможность проверить свои ответы перед тем, как передать свою работу учителю. Я написал программу на С ++ для первых нескольких упражнений, но теперь я застрял в том, как я могу проверить свой ответ со следующей проблемой:
char a, b;
short c;
a = -58;
c = -315;
b = a >> 3;
и нам нужно показать двоичное представление в памяти a
, b
а также c
,
Я сделал это на бумаге, и это дает мне следующие результаты (все двоичные представления в памяти чисел после дополнения двух):
a = 00111010 (это символ, поэтому 1 байт)
b = 00001000 (это символ, поэтому 1 байт)
c = 11111110 11000101 (это короткий, поэтому 2 байта)
Есть ли способ проверить мой ответ? Есть ли в C++ стандартный способ показать двоичное представление в памяти числа, или мне нужно самому кодировать каждый шаг (вычислить дополнение к двум, а затем преобразовать в двоичный код)? Я знаю, что последнее не займет много времени, но мне любопытно, есть ли стандартный способ сделать это.
13 ответов
Самый простой способ - создать std::bitset
представляющих значение, а затем передать его в cout
,
#include <bitset>
...
char a = -58;
std::bitset<8> x(a);
std::cout << x;
short c = -315;
std::bitset<16> y(c);
std::cout << y;
Используйте преобразование "на лету" в std::bitset
, Нет временных переменных, нет циклов, нет функций, нет макросов.
#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
В С++ 20 вы сможете использоватьсделать это:
unsigned char a = -58;
std::cout << std::format("{:b}", a);
Выход:
11000110
А пока вы можете использовать библиотеку {fmt} , на которой она основана. {fmt} также обеспечивает
print
функция, которая делает это еще проще и эффективнее ( godbolt ):
unsigned char a = -58;
fmt::print("{:b}", a);
Отказ от ответственности : я автор {fmt} и C++20.
std::format
.
Если вы хотите отобразить битовое представление любого объекта, а не просто целое число, не забудьте сначала переосмыслить его как массив символов, затем вы можете распечатать содержимое этого массива в шестнадцатеричном или даже двоичном виде (через набор битов):
#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)
работает.
Есть ли в C++ стандартный способ показать двоичное представление в памяти числа [...]?
Нет, нет std::bin
, лайк std::hex
или же std::dec
, но не сложно вывести двоичный номер самостоятельно:
Вы выводите самый левый бит, маскируя все остальные, сдвигая влево, и повторяете это для всех битов, которые у вас есть.
(Количество битов в типе sizeof(T) * CHAR_BIT
.)
Подобно тому, что уже опубликовано, просто используя бит-сдвиг и маску, чтобы получить бит; пригодный для любого типа, являющийся шаблоном (только не уверенный, если есть стандартный способ получить число бит в 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);
}
}
Многоразовая функция:
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);
}
Это работает со всеми видами целых чисел.
Использование ответов 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
У меня была эта проблема, когда я играл в соревновательные онлайн-игры по кодированию. Вот решение, которое быстро реализуется и довольно интуитивно понятно. Это также позволяет избежать вывода начальных нулей или полагаться на<bitset>
std::string s;
do {
s = std::to_string(r & 1) + s;
} while ( r>>=1 );
std::cout << s;
Однако вы должны отметить, что это решение увеличит время выполнения, поэтому, если вы конкурируете за оптимизацию или не конкурируете вообще, вам следует использовать одно из других решений на этой странице.
#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
}
Используя старую версию C++, вы можете использовать этот фрагмент:
template<typename T>
string toBinary(const T& t)
{
string s = "";
int n = sizeof(T)*8;
for(int i=n; 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 = ã => 111000110
b = ° => 111111000
c = -315 => 11111111011000101
Вот верный способ получить двоичное представление числа:
unsigned int i = *(unsigned int*) &x;
Это то, что вы ищете?
std::cout << std::hex << val << std::endl;