I am trying to port some C code into Java and have been struggling with interpreting the order of casting, operator precedence, and making sure the result is what I expect. I've read numerous posts and think I have it figured out but want to be sure I've represented it correctly.
The original C code I am trying to port is this:
UInt32 _strtoul(char *str, int size, int base)
{
UInt32 total = 0;
int i;
for (i = 0; i < size; i++)
{
if (base == 16)
total += str[i] << (size - 1 - i) * 8;
else
total += ((unsigned char) (str[i]) << (size - 1 - i) * 8);
}
return total;
}
In the code, a 4-byte value (either byte array or string) is converted into a 32-bit integer. I am attempting to understand the difference in the two clauses in the conditional; specifically, what the practical effect of the (unsigned char)
cast is.
From my understanding, in C, a byte is promoted to an int prior to the shift left. However, I'm not understanding how that translates to the bitwise representation in C. Is it correct that in the top branch (base == 16, signed) a byte value of 0xff (-1) would be promoted from 0xff to 0xffffffff while in the bottom branch (unsigned) a value of 0xff (255) would be promoted from 0xff to 0x000000ff?
Given this interpretation, is the following Java code a faithful representation (other than the Uint vs. int return type)?
public static int strtoul(byte[] bytes, int size, int base) {
int total = 0;
for (int i = 0; i < size; i++) {
if (base == 16) {
// signed bytes, shifted
total += bytes[i] << (size - 1 - i) * 8;
} else {
// unsigned bytes, shifted
total += bytes[i] & 0xff << (size - 1 - i) * 8;
}
}
return total;
}
As per Java's operator precedence, you're gonna need to put parentheses around bytes[i] & 0xff
, otherwise it's gonna get parsed as bytes[i] & (0xff << (size - 1 - i) * 8)
.
So in the end your code should look like this:
public static int strtoul(byte[] bytes, int size, int base) {
int total = 0;
for (int i = 0; i < size; i++) {
if (base == 16) {
// signed bytes, shifted
total += bytes[i] << (size - 1 - i) * 8;
} else {
// unsigned bytes, shifted
total += (bytes[i] & 0xff) << (size - 1 - i) * 8;
}
}
return total;
}