11

I've a few lines of code within a project, that I can't see the value of...

buffer[i] = (currentByte & 0x7F) | (currentByte & 0x80);

It reads the filebuffer from a file, stored as bytes, and then transfers then to buffer[i] as shown, but I can't understand what the overall purpose is, any ideas?

Thanks

Dave
  • 6,905
  • 2
  • 32
  • 35

7 Answers7

9

As the other answers already stated, (currentByte & 0x7F) | (currentByte & 0x80) is equivalent to (currentByte & 0xFF). The JLS3 15.22.1 says this is promoted to an int:

When both operands of an operator &, ^, or | are of a type that is convertible (§5.1.8) to a primitive integral type, binary numeric promotion is first performed on the operands (§5.6.2). The type of the bitwise operator expression is the promoted type of the operands.

because JLS3 5.6.2 says that when currentByte has type byte and 0x7F is an int (and this is the case), then both operands are promoted to int.

Therefore, buffer will be an array of element type int or wider.

Now, by performing & 0xFF on an int, we effectively map the original byte range -128..127 into the unsigned range 0..255, an operation often used by java.io streams for example.

You can see this in action in the following code snippet. Note that to understand what is happening here, you have to know that Java stores integral types, except char, as 2's complement values.

byte b = -123;
int r = b;
System.out.println(r + "= " + Integer.toBinaryString(r));
int r2 = b & 0xFF;
System.out.println(r2 + "= " + Integer.toBinaryString(r2));

Finally, for a real-world example, check out the Javadoc and implementation of the read method of java.io.ByteArrayInputStream:

/**
 * Reads the next byte of data from this input stream. The value 
 * byte is returned as an <code>int</code> in the range 
 * <code>0</code> to <code>255</code>. If no byte is available 
 * because the end of the stream has been reached, the value 
 * <code>-1</code> is returned. 
 */
public synchronized int read() {
return (pos < count) ? (buf[pos++] & 0xff) : -1;
}
eljenso
  • 16,789
  • 6
  • 57
  • 63
4
 (currentByte & 0x7F) | (currentByte & 0x80)

is equivalent to

 currentByte & (0x7F | 0x80)

which equals

 currentByte & 0xFF

which is exactly the same as

 currentByte

Edit: I only looked at the right side of the assignment, and I still think the equivalance is true.

However, it seems like the code wants to cast the signed byte to a larger type while interpreting the byte as unsigned.

Is there an easier way to cast signed-byte to unsigned in java?

Timbo
  • 27,472
  • 11
  • 50
  • 75
  • The last step is wrong, because negative bytes would be sign-extended to negative integers, whereas currentByte & 0xFF is positive. – starblue Feb 18 '09 at 13:07
  • There's nothing in the code that implies buffer is an array of type wider than byte. – Welbog Feb 18 '09 at 13:09
  • @Welbog There's nothing in the code that implies buffer is an array of byte. – starblue Feb 18 '09 at 13:11
  • 1
    buffer is of element type int or wider, otherwise it doesn't compile. – eljenso Feb 18 '09 at 13:20
  • Also, there's no such thing as an unsigned byte in Java. – Hank Gay Feb 18 '09 at 13:32
  • The concept of unsigned might still have existed in the mind of the programmer . . . – Timbo Feb 18 '09 at 13:33
  • This is indeed the best? way of using a byte as unsigned, and as eljenso notes, the buffer[] array must be at least int (otherwise it won't compile), thus the "cast to unsigned" is necessary, although overcompilcated. It should simply be: buffer[i] = currentByte & 0xff; – mitchnull Feb 18 '09 at 13:53
3

I think someone did too much thinking here. That's just not right.

I have but one remark

  • The original author was worried about the run-time replacing the byte with a native signed integer (presumably 32-bit) and is explicitly trying to tell us something about the sign bit being "special"?

It's code left behind. Unless you know you're on a fishy run-time? What's the type of the 'buffer' anyway?

John Leidegren
  • 59,920
  • 20
  • 131
  • 152
  • Both are arrays os bytes I tried the suggestion from Timbo, and its fubared when changed :-/ – Dave Feb 18 '09 at 13:09
  • buffer is of element type int or wider, otherwise it shouldn't compile. – eljenso Feb 18 '09 at 13:19
  • @Dave Very strange, what are the symptoms? – starblue Feb 18 '09 at 13:32
  • Well its part of a video codec, and this is the fileinputmanager, at various points I eventually hit (almost instantaneously) nullpointer exceptions and array out of bounds... :( – Dave Feb 18 '09 at 14:00
  • We need to see more of the code where do all the variables come from? 'buffer' or 'filebuffer' could be null and currentPosition can be out of bounds... need... more... source... – John Leidegren Feb 18 '09 at 14:36
  • The original author remapped -128..127 signed range onto 0..255 unsigned range, which is not an unusual operation when manipulating audio/video streams. That's really all there is to it. – eljenso Feb 18 '09 at 15:21
  • If so a reinterpret_cast or for that matter static_cast, would accomplish the same thing. – John Leidegren Feb 18 '09 at 15:43
  • This question is tagged Java. – eljenso Feb 18 '09 at 23:14
2

The complicated bitwise logic is completely superfluous.

for (int i = 0; i < buffer.length; i++) {
    buffer[i] = filebuffer[currentPosition + i] & 0xff;
}

does the same thing. If buffer is declared as an array of bytes you may even leave out the & 0xff, but unfortunately the declaration is not shown.

The reason may be that the original developer was confused by bytes being signed in Java.

starblue
  • 55,348
  • 14
  • 97
  • 151
2

The result of a bitwise AND operation has a 1 on that bits where both bits are 1 while the result of a bitwise OR operation hase a on that bits where either one of bot bits is 1.

So an example evaluation for the value 0x65:

  01100101 0x65
& 01111111 0x7F
===============
  01100101 0x65

  01100101 0x65
& 10000000 0x80
===============
  00000000 0x00

  01100101 0x65
| 00000000 0x00
===============
  01100101 0x65
Gumbo
  • 643,351
  • 109
  • 780
  • 844
0

The good thing about these kinds of logical operations: you can try every possible combination (all 256 of them) and verify that you get the answer you expected.

Adrian Pronk
  • 13,486
  • 7
  • 36
  • 60
0

Turns out, the file which the byte was being read from was in a signed bit notation, and of a different length, therefore it was requried to perform this task to allow it to be extended to the java int type, while retaining its correct sign :)

Dave
  • 6,905
  • 2
  • 32
  • 35