I am looking for the fastest way to read numerical values stored in binary files.
I have done some functions that seem to work, but I'd like to get a feedback on whether or not my implementation is good.
Here is how I get a signed integer from a 4-bytes little endian block:
signed long int from4li(char const * const buffer)
{
signed long int value = 0;
value += (unsigned char) buffer[3];
value <<= 8;
value += (unsigned char) buffer[2];
value <<= 8;
value += (unsigned char) buffer[1];
value <<= 8;
value += (unsigned char) buffer[0];
return value;
}
This would also work for unsigned integers, but I've originally made a different implementation for unsigned integers (that fails with signed integers, I don't know exactly why):
unsigned long int fromu4li(char const * const buffer)
{
unsigned long int value = 0;
value += (unsigned char) buffer[0] << 8 * 0;
value += (unsigned char) buffer[1] << 8 * 1;
value += (unsigned char) buffer[2] << 8 * 2;
value += (unsigned char) buffer[3] << 8 * 3;
return value;
}
I am more sure about the conversion from an integer to a little endian string buffer, which I think probably couldn't be optimized further:
void to4li(long int const value, char * const buffer)
{
buffer[0] = value >> 8 * 0;
buffer[1] = value >> 8 * 1;
buffer[2] = value >> 8 * 2;
buffer[3] = value >> 8 * 3;
}
I also think that it could be even faster usign memcpy, but to use memcpy I have to know the endianness of the host system.
I don't really want to rely on the endianness of the host system, as I think that my code should be independent of the internal data representation of the host system.
So, is this a proper way of doing those conversions, or can I improve my functions?
uint32_t integer = (c0 << 0) | (c1 << 8) | (c2 << 16) | (c3 << 24)anduint8_t *buf = (uint8_t *)&number; c0 = buf[0]; c1 = buf[1];etc. - user529758uint32_t integer = (c0 << 0) | (c1 << 8) | (c2 << 16) | (c3 << 24)seems like a nice way. But how is it going to work with signed numbers? - alexpirineuint32_t integer = (c0 << 0) | (c1 << 8) | (c2 << 16) | (c3 << 24);, thenint32_t signed_integer = (int32_t)(integer);will make it become signed numbers. - MYMNeoc0,c1, … need to be of typeunsigned charso it can work (see example in answer). Why? - alexpirinecharis signed or unsigned. If you want one or the other, and care about your code being portable, you have to specify which one you want. Otherwise, if it's signed, it will be sign-extended in order to turn it into anintto work with the<<operator. As a char, -1 turns into 0xff...but as an int, -1 turns into 0xffffffff. And that's assuming your numbers are two's complement, which (although it's by far the most common representation of integer types) isn't assumed by the standard either, and portable code can't assume it. - cHao