The Rantings and Ravings of an Unremarkable Geek

Categories : All | Java

Today I stumbled on a relatively straightforward problem and got stuck for a few minutes because of a coding brain-fart. I'm going to mention the problem and hope that one day my description may save some poor coder a few minutes of confusion.

Here's the story: Narrowing conversions in Java are pretty predictable. If you go from an int to a short, the 16 most significant bits disappear. That's all there is to it. Widening conversions are a little different. If you have the value -2 as a byte (11111110), you'd like it to still be -2 when it's widened into a short (1111111111111110). The extension of 1's for negative numbers is called sign extension. Another place where sign extension shows up is with the >> operator which shifts in 1's for negative numbers. Everything you could ever want to know about this stuff is in the Java Language Specification.

Today I was writing some code for a binary network protocol and I wanted to break a single short value into two bytes and also reverse the process on the other side of the network. Typically you can use a DataOutputStream and never think for a moment about binary, but in this case it was non-blocking IO and doing the conversion manually made the most sense in context. Let's imagine the server code looked something like this:

    public void testSplitSplice() {
        Random random = new Random(Double.doubleToLongBits(Math.PI));
        for (int i = 0; i < 1000000; i++) {
            short shortValue = (short) random.nextInt();
            byte hiByte = hibyte(shortValue);
            byte loByte = lobyte(shortValue);
            assertEquals(shortValue, splice(hiByte, loByte));
        }
    }

The goal is to write functions hibyte(short), lobyte(short), and splice(byte,byte) that will pass this test. The hibyte and lobyte functions are pretty clear and I wrote those correctly on the first try:

    private byte lobyte(short number) {
        return (byte) (number & 0xFF);
    }

    private byte hibyte(short number) {
        return (byte) (number >> 8);
    }

The problem was with the splice function, which looked approximately like this:

    private short splice(byte hibyte, byte lobyte) {
        return (short) ((hibyte << 8) | lobyte);
    }

Both hibyte and lobyte are only 8 bits, so this function just needs to OR them together, right? Wrong! Being the astute reader I know you are, I'm sure you immediately realized my mistake: failure to account for sign extension.

If either hibyte or lobyte is negative then the entire high byte will consist of ones. That caused some mighty interesting behavior in the server when a variable that should always be postive was negative. Fortunately a few well-placed assertions caught the negative number and I was able to work backwards from there. Here's the corrected version of the splice function:

    private short splice(byte hibyte, byte lobyte) {
        return (short) (((hibyte & 0xFF) << 8) | (lobyte & 0xFF));
    }

Lesson: Narrowing conversions chop of bits as expected. Widening conversions of negative numbers will introduce sign bits. Don't forget the sign bits!


Joppa and Cullman County.

Read more...
Parrish and Walker County.

Read more...
Carlton and Clarke County.

Read more...
Fort Rucker and Dale County.

Read more...
Buhl and Tuscaloosa County.

Read more...
Midway and Bullock County.

Read more...
Excel and Monroe County.

Read more...
Skyland and Tuscaloosa County.

Read more...
Romulus and Tuscaloosa County.

Read more...
Ozark and Dale County.

Read more...
Crestline Heights and Jefferson County.

Read more...
Little Brooklyn and Conecuh County.

Read more...
Huntsville and Madison County.

Read more...
Choccolocco and Calhoun County.

Read more...
Ashford and Houston County.

Read more...
Guntersville and Marshall County.

Read more...