I have a slightly different point of view. The OP is using bit shifting correctly to get into little endian, so the C++ portability will be fine unless he's dealing with a byte of unconventional size. The communication protocol goes against the big endian over network convention, but sometimes supporting legacy systems is like that.
If the port variable has users outside the provided code, use an int and only send the bits you want as you did in your Java sample above. If you are passing that port around, it sucks to keep having to twiddle the damn sign bits and sooner or later you'll screw it up. If no one else needs to play with port, sign isn't going to matter.
byte[] data = new byte[3];
int port = 5025; // short or int doesn't matter in this case
data[0] = 1;
data[1] = (byte)(port & 0xff);
data[2] = (byte)((port >> 8) & 0xff);
When reading back in and getting 65440, it looks like you used a char and your bytes got sign extended by the shift. Here is a bit of test code so you can play around and see what's happening.
#include <cstdio>
int main()
{
unsigned short val = 32896;
char hi = (char)((val >> 8) & 0xFF);
char lo = (char)(val &0xFF);
printf("Watch what the sign bit can do to the bytes here:\n");
printf("Value: %d, raw in hex: %04x, Hi byte: %02x, Low byte: %02x\n", val, val, hi, lo);
printf("This one only works if the low byte doesn't sign extend\n");
char datas[3] = {0, hi, lo};
unsigned short port = (datas[1] << 8) | datas[2];
printf("Reassembled short: %u, In Hex: %04x\n", port, port);
printf("This one works, but will not for an integer\n");
port = (datas[1] << 8) | (datas[2] & 0xFF);
printf("Reassembled short: %u, in Hex: %04x\n", port, port);
unsigned int bigport = (datas[1] << 8) | (datas[2] & 0xFF);
printf("Reassembled int: %u, in Hex: %04x\n", bigport, bigport);
printf("With unsigned characters it just works\n");
unsigned char datau[3] = {0, hi, lo};
port = (datau[1] << 8) | datau[2];
printf("Reassembled short: %u, In Hex: %04x\n", port, port);
bigport = (datau[1] << 8) | (datau[2] & 0xFF);
printf("Reassembled int: %u, in Hex: %04x\n", bigport, bigport);
}
output:
Watch what the sign bit can do to the bytes here:
Value: 32896, raw in hex: 8080, Hi byte: ffffff80, Low byte: ffffff80
This one only works if the low byte doesn't sign extend
Reassembled short: 65408, In Hex: ff80
This one works, but will not for an integer
Reassembled short: 32896, in Hex: 8080
Reassembled int: 4294934656, in Hex: ffff8080
This one just works
Reassembled short: 32896, In Hex: 8080
Reassembled int: 32896, in Hex: 8080
So what happened?
(datas[1] << 8) | datas[2]
Both numbers must be scaled up to short and they are signed, so 0x80 becomes 0xFF80. Actually, they become integers, but that's another story.
(0xFF80 << 8) | 0xFF80
Simplifies to
0x8000 | 0xFF80
And that ORs to
0xFF80
AKA 65408, not 32896.
In this case unsigned char is your friend. There may have been problems with the Java, but the C++ is definitely broken.
data[1] << 8is04<<8and becomes 0400. Nice.data[2]is 80 (-128), but it's about to be combined with a 16 bit number, so it becomes FF80 (-128 in signed 16 bits).0400|FF80=FF80 (65408 in unsigned 16 bits). You have to fix the C++ code. It is broken. - user4581301