Как распечатать (используя cout) число в двоичной форме?

Я слежу за курсом в колледже по операционным системам, и мы учимся конвертировать из двоичного в шестнадцатеричный, десятичный в шестнадцатеричный и т. Д., И сегодня мы только что узнали, как числа со знаком / без знака хранятся в памяти с использованием дополнения до двух (~ число + 1).

У нас есть пара упражнений, которые нужно выполнить на бумаге, и я хотел бы иметь возможность проверить свои ответы, прежде чем отправлять свою работу учителю. Я написал программу на C ++ для первых нескольких упражнений, но теперь я застрял в том, как я могу проверить свой ответ со следующей проблемой:

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 ++ стандартный способ показать двоичное представление числа в памяти или мне нужно самому кодировать каждый шаг (вычислять два дополнения и затем преобразовывать в двоичное)? Я знаю, что последнее не займет так много времени, но мне любопытно, есть ли стандартный способ сделать это.


person Jesse Emond    schedule 08.09.2011    source источник
comment
вы понимаете шестнадцатеричное представление? если вы это сделаете, вы можете распечатать шестнадцатеричное представление (с помощью std::hex) манипулятора - я оставлю это как упражнение, чтобы вы отработали остальное ...   -  person Nim    schedule 08.09.2011
comment
Вы много подчеркиваете в памяти, но я надеюсь, что они не заставляют вас решать проблемы с порядком байтов.   -  person Mark Ransom    schedule 08.09.2011
comment
Вы хоть представляете, что такое endianness? Если да, позаботится ли он об этом в этом упражнении? Ответ на эти вопросы может повлиять на ответ на ваш вопрос.   -  person R. Martinho Fernandes    schedule 08.09.2011
comment
В зависимости от вашей IDE, если вы просто хотите проверить правильность написанного от руки решения, а не пишете программу для отображения чего-то полезного, вы можете использовать что-то вроде средства просмотра памяти Visual Studio для просмотра точного содержимого памяти.   -  person Kiley Naro    schedule 08.09.2011
comment
Калькулятор Windows сделает это за вас. Если вы не работаете в Windows, я уверен, что другие операционные системы тоже имеют такую ​​возможность.   -  person sbi    schedule 08.09.2011
comment
Даже Google делает это, например, «-58 в двоичном формате» - но +1 за желание узнать, как это сделать самому в коде.   -  person Konrad Rudolph    schedule 08.09.2011


Ответы (12)


Самый простой способ - это, вероятно, создать 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';
person Jerry Coffin    schedule 08.09.2011
comment
Извините за мое незнание, но покажет ли это только двоичное представление числа (например, 8 будет 00001000) или его представление в памяти (например, как -8 будет сохранено, если позаботиться о знаковом бите и использовать два дополнения)? - person Jesse Emond; 08.09.2011
comment
Аргумент конструктора @Jesse: bitset интерпретируется как беззнаковое значение, которое работает так же, как два дополнения. Строго говоря, C ++ не гарантирует арифметику дополнения до двух, а также операция -58 >> 3 в вашем примере не определена. - person Potatoswatter; 08.09.2011
comment
Могу ли я преобразовать значение битового набора (например, x или y в этом примере) в char *? - person nirvanaswap; 16.03.2016
comment
@nirvanaswap: Я полагаю, вы можете его разыграть, но результат вряд ли будет полезен. Если вам нужен результат в виде строки, используйте член to_string bitset. - person Jerry Coffin; 16.03.2016
comment
Спасибо, Джерри, через несколько минут я обнаружил to_string. К вашему сведению, приведение типов не работает, переменная bitset - это объект какого-то действительно загадочного класса bitset3ul (?!). Лучше пусть абстракции делают всю работу! - person nirvanaswap; 16.03.2016
comment
как это сделать на C? Также я хочу спросить, когда выполняется дополнение 2, например, если я пишу unsigned int a = 2, а когда подписано int a = 2, делаю подписанное одно хранилище 2 как 2 дополнения 11111111 11111111 11111111 11111101 или сохраняется обычным способом 00000000 00000000 00000000 00000010. каков решающий фактор, выполнять дополнение 2 или нет? Этот вопрос меня беспокоит какое-то время. - person Suraj Jain; 29.12.2016
comment
Как разделить байты при печати битов? - person Beyondo; 18.08.2019
comment
Хорошо, ничего страшного; Я пробовал получить битовую строку через bitset::to_string(), затем использовал этот полезный ответ для разделения пробелом каждые 8 ​​бит: < б> separate<8, ' '>(s); - person Beyondo; 18.08.2019
comment
std::cout << std::bitset<8>(a); << std::endl - хороший лайнер - person Ruan; 21.04.2020

Используйте "на лету" преобразование в 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
person r233967    schedule 17.03.2013
comment
Обратите внимание, что размер жесткого кодирования не требуется. Например. для печати x используйте: std::cout << std::bitset<8*sizeof(x)>(x). - person Apollys supports Monica; 15.03.2019

Если вы хотите отобразить битовое представление любого объекта, а не только целого числа, не забудьте сначала переинтерпретировать его как массив символов, затем вы можете распечатать содержимое этого массива в шестнадцатеричном или даже двоичном виде (через битовый набор):

#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).

person Cubbi    schedule 08.09.2011

В 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.

person vitaut    schedule 16.12.2020
comment
std::format еще не доступен в Visual Studio 2019, не так ли? - person rturrado; 10.04.2021
comment
Это не так, но они над этим работают. - person vitaut; 11.04.2021

Есть ли в C ++ стандартный способ показать двоичное представление числа в памяти [...]?

Нет. Нет std::bin, например std::hex или std::dec, но вывести двоичное число самостоятельно несложно:

Вы выводите самый левый бит, маскируя все остальные, сдвиг влево и повторяя это для всех битов, которые у вас есть.

(Количество бит в типе sizeof(T) * CHAR_BIT.)

person sbi    schedule 08.09.2011

Подобно тому, что уже опубликовано, просто используется битовый сдвиг и маска, чтобы получить бит; может использоваться для любого типа, будучи шаблоном (только не уверен, есть ли стандартный способ получить количество бит в 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);
    }
}
person eudoxos    schedule 08.09.2011
comment
Стандартный способ получить количество бит на байт - это макрос CHAR_BIT. - person R. Martinho Fernandes; 08.09.2011
comment
Похоже, что sbi отредактировал сообщение Εύδοξος в соответствии с комментарием @R.MartinhoFernandes. Однако последнее предложение он не изменил. Буду редактировать. - person gsamaras; 31.10.2018

Функция многоразового использования:

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

Это работает со всеми видами целых чисел.

person Shital Shah    schedule 04.06.2018

Используя старую версию 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
person Ratah    schedule 14.04.2019
comment
Печать неправильного количества бит. 111000110 - это 9 бит, а не 8. - person David Ledger; 16.10.2019
comment
Я допустил ошибку границы, пожалуйста, проверьте сейчас - person Ratah; 28.10.2019

Использование ответов 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
person user5673656    schedule 02.05.2020

Вот истинный способ получить двоичное представление числа:

unsigned int i = *(unsigned int*) &x;
person user5463518    schedule 19.10.2015
comment
Нет ; это просто копирует x в i. Если только вы не имели в виду это как шутку? - person AnthonyD973; 02.09.2018

Это то, что вы ищете?

std::cout << std::hex << val << std::endl;
person Kevin    schedule 08.09.2011
comment
Замечание модератора Я попытался выборочно удалить антагонистические или иным образом неконструктивные комментарии под этим ответом, и в итоге у меня получился очень прерванный разговор. Все комментарии были удалены. Пожалуйста, делайте комментарии профессиональными, конструктивными и, прежде всего, по теме. Если бы OP хотел удалить это, OP уже удалил бы его. Если вы не согласны с таким ответом, тогда голосуйте. Если вы можете улучшить этот ответ, отредактируйте. </argument>. Неужели мы взрослые, да? Я почти проверил возраст всех, кто здесь прокомментировал, чтобы убедиться, что всем больше 13 лет. - person Tim Post♦; 08.09.2011

person    schedule
comment
Разве это не должно быть int t = pow(2, num_of_bits - 1);? - person BmyGuest; 06.04.2018