2 things:
char can be signed or unsigned, hence shouldn't be used storing for data types other than characters.
In C, C++ and most C-like languages, any types narrower than int must be promoted to int in an expression, and your statement will be treated like this
unsigned long ret = ((int)b[0] << 56) | ((int)b[1] << 48)
| ((int)b[2] << 40) | ((int)b[3] << 32)
| ((int)b[4] << 24) | ((int)b[5] << 16)
| ((int)b[6] << 8) | ((int)b[7]);
If char is signed, it'll be promoted to int using sign extension. As a result the top bits will be filled with 1s if the byte value is negative.
In MSVC char is signed by default. You can use /J to make char unsigned, which will solve part of your problem. But then another problem arises:
In Windows long is a 32-bit type, consequently you can't pack 8 bytes into it. Moreover int is also 32-bit on most modern systems, and after promoting b[i] to int shifting more than 31 is undefined behavior which is what your program does.
So to fix all the problems portably you need to:
- Cast all
b[i] to unsigned char or uint8_t, or masking the high bits by ANDing it with 0xFF like 0605002 suggested. Or simply change the type of b to unsigned char&* instead of char&*
- Change the return type to a type at least 64-bit wide like
(unsigned) long long, (u)int64_t or (u)int_least64_t
The result may look like this
uint64_t readAndSkipLong(unsigned char*& b)
{
return ((uint64_t)b[0] << 56) | ((uint64_t)b[1] << 48)
| ((uint64_t)b[2] << 40) | ((uint64_t)b[3] << 32)
| ((uint64_t)b[4] << 24) | ((uint64_t)b[5] << 16)
| ((uint64_t)b[6] << 8) | ((uint64_t)b[7]);
}
or
uint64_t readAndSkipLong(char*& b)
{
return ((uint64_t)(uint8_t)b[0] << 56) | ((uint64_t)(uint8_t)b[1] << 48)
| ((uint64_t)(uint8_t)b[2] << 40) | ((uint64_t)(uint8_t)b[3] << 32)
| ((uint64_t)(uint8_t)b[4] << 24) | ((uint64_t)(uint8_t)b[5] << 16)
| ((uint64_t)(uint8_t)b[6] << 8) | ((uint64_t)(uint8_t)b[7]);
}
However you don't actually need to write a function to reverse endian. There are already ntohll() and htonll() for that purpose
reversedEndian = ntohll(originalValue);
If the input must be a char array then just copy the value to a uint64_t
memcpy(&originalValue, &b, sizeof originalValue);
reversedEndian = ntohll(originalValue);
You can further reduce the whole thing to reversedEndian = ntohll(*(int64_t*)&b); if strict aliasing is allowed because on x86 unaligned access is generally permitted