Почему бинарный эквивалентный расчет становится неверным?

Я написал следующую программу для вывода двоичного эквивалента целочисленного значения (я проверил, что int в моей системе имеет 4 байта), он имеет 4 байта. Но выход не подходит. Код:

#include<iostream>
#include<iomanip>
using namespace std;

void printBinary(int k){
    for(int i = 0; i <= 31; i++){
        if(k & ((1 << 31) >> i))
            cout << "1";
        else 
            cout << "0";
    }
}

int main(){
    printBinary(12);
}

Где я ошибаюсь?

Ответы

Ответ 1

Проблема в 1<<31. Поскольку 2 31 не может быть представлено с 32-разрядным знаковым целым числом (диапазон -2 31 до 2 31 - 1), результат undefined [1].

Исправить легко: 1U<<31.


[1]: поведение определяется реализацией с С++ 14.

Ответ 2

Это выражение неверно:

if(k & ((1<<31)>>i))

int является подписанным типом, поэтому, когда вы сдвигаете 1 31 раз, он становится битом знака в вашей системе. После этого смещение результата right i times sign - увеличивает число, что означает, что верхние бит остаются 1 s. Вы получите последовательность, которая выглядит так:

80000000 // 10000...00
C0000000 // 11000...00
E0000000 // 11100...00
F0000000 // 11110...00
F8000000
FC000000
...
FFFFFFF8
FFFFFFFC
FFFFFFFE // 11111..10
FFFFFFFF // 11111..11

Чтобы исправить это, замените выражение на 1 & (k>>(31-i)). Таким образом, вы избежите поведения undefined * вызванного сдвигом 1 в позицию знакового бита.

*С++ 14 изменил определение, чтобы сдвинуть 1 31 раз влево в 32-битном int больше не undefined (Спасибо, Мэтт Макнабб, за это указали).

Ответ 3

Типичное представление внутренней памяти знакового целочисленного значения выглядит следующим образом:

введите описание изображения здесь

m ost s b он (первый справа) - это знаковый бит и signed numbers (например, int) он представляет, является ли число отрицательным или нет. Когда вы переносите дополнительные биты Расширение знака выполняется для сохранения знака числа. Это делается с помощью добавления цифр к наиболее значимой стороне числа. (В соответствии с процедурой, зависящей от конкретного используемого имени числа).
В беззнаковых числах первый бит из правой представляет собой только MSB представленного числа, поэтому, когда вы переносите дополнительные биты, расширение знака не выполняется.

Примечание: перечисление бит начинается с 0, поэтому 1 << 31 заменяет ваш бит знака, и после этого каждая операция сдвига бит влево >> приводит к расширению знака. (как указывает @dasblinkenlight)

Итак, простое решение вашей проблемы состоит в том, чтобы сделать число без знака (это то, что U делает в 1U << 31), прежде чем вы начнете манипулировать бит. (как указывает @Yu Hao)

Для дальнейшего чтения см. подписанные представления числа и два дополнения.(as это наиболее распространенный)