Tuesday, September 8, 2015

Be careful with operator precedence

I recently encountered the following bug while programming in Java. I've taken it out of context and created the program below for illustrative purposes.

The goal is to add two byte values while avoiding overflow. To this end, we cast them to integers, and we use bit-masking to avoid sign extension when casting.  The unsuccessful version is highlighted in red, while the successful version is green:

public class ConvertBytes {
 public static void main(String[] args) {
  byte a = 127;
  byte b = 126;
  int bad = ((int)a) & 0xff + ((int)b) & 0xff;
  System.out.println(bad);
  int good = ((int)a & 0xff) + ((int)b & 0xff);
  System.out.println(good);
 }
}

When this program is executed, bad is 125 and good is 253.

I can't believe that after 13 years as an active Java programmer (with 11 years before that as an active C++ programmer) I made so elementary a mistake, but I'm posting it here in hopes it will be a useful warning to others.  For whatever reason, I assumed that bitwise-and had a higher precedence than addition, perhaps because it is a traditionally "multiplicative" operator.  As it turns out, its precedence is actually much lower.

A further observation is that this is not what I thought the bug was originally.  At first, I thought I had somehow messed up the casting.  It was only after I rechecked it carefully that I realized I was killing the higher-order bits with the bitwise and.

No comments:

Post a Comment