18

I wrote the following program to output the binary equivalent of a integer taking(I checked that int on my system is of 4 bytes) it is of 4 bytes. But the output doesn't come the right. The code is:

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

Where am I getting it wrong?

Ziezi
  • 6,375
  • 3
  • 39
  • 49

3 Answers3

29

The problem is in 1<<31. Because 231 cannot be represented with a 32-bit signed integer (range −231 to 231 − 1), the result is undefined [1].

The fix is easy: 1U<<31.


[1]: The behavior is implementation-defined since C++14.

Yu Hao
  • 119,891
  • 44
  • 235
  • 294
  • 3
    [Since C++14](http://stackoverflow.com/questions/26331035/why-was-1-31-changed-to-be-implementation-defined-in-c14) there is no UB – M.M Sep 01 '15 at 12:02
  • 4
    @MattMcNabb: I don't see the OP tagged as C++14 – dhein Sep 01 '15 at 13:36
  • 4
    @MattMcNabb: your phrasing sounds like you want to show that Yu Hao is incorrect. My point is, he isn't since the OP wasn't stating a specific version. – dhein Sep 01 '15 at 13:54
  • @Zaibis He is incorrect regarding the current version of C++. I am trying to give additional information . – M.M Sep 01 '15 at 22:52
  • @MattMcNabb: And I tryed to prevent confusion for future readers. So I'd say we did well my friend ;) – dhein Sep 02 '15 at 07:31
8

This expression is incorrect:

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

int is a signed type, so when you shift 1 31 times, it becomes the sign bit on your system. After that, shifting the result right i times sign-extends the number, meaning that the top bits remain 1s. You end up with a sequence that looks like this:

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

To fix this, replace the expression with 1 & (k>>(31-i)). This way you would avoid undefined behavior* resulting from shifting 1 to the sign bit position.

* C++14 changed the definition so that shifting 1 31 times to the left in a 32-bit int is no longer undefined (Thanks, Matt McNabb, for pointing this out).

Community
  • 1
  • 1
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • While it's technically correct explanation looking at how the instructions are executed on the machine, the language standard leaves the behavior undefined for `1 << 31`. From the specs: `The value of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits are zero-filled. [...] Otherwise, if E1 has a signed type and non-negative value, and E1 × 2^E2 is representable in the result type, then that is the resulting value; otherwise, the behavior is undefined.` – nhahtdh Sep 01 '15 at 09:43
  • @nhahtdh That's why I wrote that this is the behavior on OP's system. – Sergey Kalinichenko Sep 01 '15 at 09:45
  • I think you should make it more prominent, and also clarify the fact that while your fix may be correct on the OP's system, it is undefined behavior according to the specs. – nhahtdh Sep 01 '15 at 09:53
4

A typical internal memory representation of a signed integer value looks like:

enter image description here

The most significant bit (first from the right) is the sign bit and in signed numbers(like int) it represents whether the number is negative or not. When you shift additional bits sign extension is performed to preserve the number's sign. This is done by appending digits to the most significant side of the number.(following a procedure dependent on the particular signed number representation used).
In unsigned numbers the first bit from the right is just the MSB of the represented number, thus when you shift additional bits no sign extension is performed.

Note: the enumeration of the bits starts from 0, so 1 << 31 replaces your sign bit and after that every bit shift operation to the left >> results in sign extension. (as pointed out by @dasblinkenlight)

So, the simple solution to your problem is to make the number unsigned (this is what U does in 1U << 31) before you start the bit manipulation. (as pointed out by @Yu Hao)

For further reading see signed number representations and two's complement.(as it's the most common)

LThode
  • 1,843
  • 1
  • 17
  • 28
Ziezi
  • 6,375
  • 3
  • 39
  • 49