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 |
| 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(); |
//doing nothing extra |
*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(); // assuming you have your stream already set up
short b = (short)(a & 0xff);
short c = inputStream.readShort();