Converting C++ Unsigned Numbers to Java

Dealing with unsigned values from C++ can seem like a headache sometimes, if you don’t understand what’s going on “under the hood”. Luckily you don’t have to understand everything under the hood to read a binary file written by a C++ app in Java or vice versa, just have a vague understanding of the issues involved..

The major differences that can cause challenges are:
1) Figuring out which data types are “equivalent”
2) Java doesn’t have unsigned types, but C++ types can be signed or unsigned.
3) Some types just don’t have a direct equivalent (eg: C++ float has no exact match in Java)

Here’s a table showing how internally C++ (on a 32-bit version of Windows) and Java store integer types:

Size 1 byte 2 bytes 4 bytes 8 bytes 16 bytes
8 bits 16 bits 32 bits 64 bits 128 bits
C++ (on Win32) byte short int/long long long __int128
Java byte short int long BigInteger

If you are using a 64 bit operating system or a 16 bit operating system, the C++ sizes such as how many bytes an int is will vary. Microsoft invented some funky looking type names like __int32 for those times when you want to tell the compiler “when I said I wanted 4 bytes for my integer, I meant 4 bytes”, but that may only work with Microsoft compilers.

Here are some other binary data types that are frequently encountered:

Size 1 byte 2 bytes 4 bytes 8 bytes 16 bytes
8 bits 16 bits 32 bits 64 bits 128 bits
C++(on Win32) char/bool float double/long double
Java boolean char float double

Going from C++to Java:

C++Type Java Type Read from File** Then translate the value
unsigned byte (signed)short byte a=in.readByte(); short b=(short)(a&0xff);
unsigned short (signed)int short a=in.readShort(); int b=a&0xffff;
unsigned int/long (signed)long int a=in.readInt(); long b=a&0xffffffffL;
float* float int a=in.readInt(); float b=Float.intBitsToFloat(a);
double float float a=in.readFloat();

*note: because Java does not have a 4 byte float, converting 4 byte c++ float to 8 byte java float and then back to 4 byte c++ float may result in rounding errors. Use Float.floatBitsToInt(floatValue); to convert in the other direction.
** in refers to a binary input stream type of your choice.

To convert back and forth, you just cast in the to C++ direction. Easy.

Code example: (int or short could be used here just as well)

public static short toUnsigned(byte b) { 
    return (short)(b & 0xff);
}

public static byte toSigned(short i) { 
     return (byte) i; 
}

*C++ type sizes are assuming you are running a 32 bit version of Windows. You can always explicitly set your sizing by declaring the types as __int8 (unsigned __int8)

For a C++ unsigned byte (value 0 to 255), mask with 0xff and store the result in a short:

byte a = inputStream.readByte(); 
short b = (short)(a & 0xff);