javabitwise-operatorsbit-shiftsteganographybitwise-and

Java - &0xff gives bits from 8 to 31 as 1's


I have a problem while doing the AND operator using 0xff.

public Pixel(int x, int y, int p) {
    this.x = x;
    this.y = y;
    pixelValue = p;
    A = (byte) ((p>>24) & 0xff);
    R = (byte) ((p>>16) & 0xff);
    R = (byte) (R&0xff);
    G = (byte) ((p>>8) & 0xff);
    B =(byte) (p & 0xff);
    printAll();
}
void printAll() {
    System.out.println("A "+Integer.toBinaryString(A));
    System.out.println(Byte.toUnsignedInt(A));
    System.out.println("R "+Integer.toBinaryString(R));
    System.out.println(Byte.toUnsignedInt(R));
    System.out.println("G "+Integer.toBinaryString(G));
    System.out.println(Byte.toUnsignedInt(G));
    System.out.println("B "+Integer.toBinaryString(B));
    System.out.println(Byte.toUnsignedInt(B));
    System.out.println("pixelValue"+pixelValue);
    System.out.println(Integer.toBinaryString((byte)(pixelValue)));
}

When doing Pixel p = new Pixel(0,0,2145687240); I get

A 1111111
127
R 11111111111111111111111111100100
228
G 11111111111111111111111110010110
150
B 11111111111111111111111111001000
200
pixelValue-56
11111111111111111111111111001000

Question being, why are R, G and B filled with 1s? and why is A only 7 bits? why when calling &0xff I get 1111111111111111111111111100100? shouldn't this cancel everything but the first 8 bytes?


Solution

  • Bytes go from 0 to 255 inclusive since they can hold 2^8=256 values. That's the unsigned definition, at least.

    The question to ask yourself here is: how do negative numbers get represented? The typical method is using something known as the two's complement. The first bit, instead of representing 0 when off and 2^(n-1) when on, like it usually would, instead represents 0 when off and -2^(n-1) when on.

    Thus, 228 is stored internally as 11100100. If you convert this from base 2 you will see that this equals 228... but only when unsigned.

    When signed, the last 7 bits represent 100. Then, the first bit, instead of representing 128, instead represents -128. Thus, the value is -28 when signed.

    Then, when converting this to an integer, since an integer has 32 bits, then the first bit will represent -2147483648, and thus the last 31 bits will need to represent 28 + 2147483648, which is where 1111111111111111111111111100100 comes from. Thus, the 32 bit representation of -28 is 11111111111111111111111111100100.

    If you want to actually have 228, you'd probably want to call Integer.toBinaryString on the result of Byte.toUnsignedInt, which, as the name suggests, converts it as an unsigned number. The issue here is that it's being signed, which means that it's -28, not 228 like you want.