2

I stored a filesize in a binary file and I am able to get this filesize into a char[8] buffer. I would like to convert this char[] into an off_t type in order to be able to pass it as an argument of truncate(const char *path, off_t length).

I tried this naive approach and it seems to work most of the time, but it fails sometimes and gives me a weird sequence of bits.

off_t pchar_2_off_t(char* str, size_t size)
{
    off_t ret = 0;
    size_t i;
    for (i = 0; i < size; ++i)
    {
        ret <<= 8;
        ret |= str[i];
    }
    return ret;
}
Steve Vinoski
  • 19,847
  • 3
  • 31
  • 46
user1527491
  • 895
  • 10
  • 22

4 Answers4

1

Just bulk-copy the data in question:

#include <string.h> /* for memcpy() */

...

char str[8];
/* Read 8 bytes binary data into str here. */

off_t off_file;
memcpy(&off_file, str, sizeof off_file);

To get around any endiness issues just do:

off_t off = ntohll(off_file); /* Assuming ntohll being the 64bit version of ntohl(). */

As ntohll() is non-standard please see some possible ways to implement it here: 64 bit ntohl() in C++?

Community
  • 1
  • 1
alk
  • 69,737
  • 10
  • 105
  • 255
1

ret |= str[i]; is a problem as str[i] may sign-extend upon conversion to int, setting many bits in ret. Implied by @pmg and commented by @mafso

off_t pchar_2_off_t(const char* str, size_t size) {
    off_t ret = 0;
    size_t i;
    for (i = 0; i < size; ++i) {
        ret <<= 8;
        ret |= (unsigned char) str[i];
    }
    return ret;
}
Community
  • 1
  • 1
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
0
unsigned const char blah[8] = {0xdd,0xee,0xaa,0xdd,0xbb,0xee,0xee,0xff};
off_t * scalar = (off_t *) malloc(8);
memcpy(scalar, blah, 8);

printf("%llx\n",*scalar);

outputs(on my intel machine): ffeeeebbddaaeedd

what the wha?! you say.... there is a problem with this approach, and it is that it isn't portable ... it is a problem with endianness ...

so if you want to do this portably you need to actually either be aware of endianness and special case it or just convert with a loop:

*scalar = 0;
for (int i = 0; i < 8; i++)
{
    *scalar += (uint64_t)blah[i] << ( 8 * (7-i));
}

printf("%llx\n",*scalar);

outputs (on all machines that have 64bit off_t's): ddeeaaddbbeeeeff

Grady Player
  • 14,399
  • 2
  • 48
  • 76
  • This has an alignment issue. `scalar` may be more restrictive than `blah`. – chux - Reinstate Monica Feb 07 '15 at 15:47
  • Minor: As the size of `off_t` is not necessarily the same as `unsigned long long`, using `printf("%llx\n",(unsigned long long) *scalar);` is portable. Also `off_t` is signed. – chux - Reinstate Monica Feb 07 '15 at 16:00
  • If you do not know the endianess the data had been stored with, you have **no** 100% chance to correctly read the data. – alk Feb 07 '15 at 16:00
  • @alk ... there is an order for elements in an array, and there is an order for most significant bytes in a scalar value... in a big endian machine these are inter changeable; on a little endian machine it isn't... – Grady Player Feb 07 '15 at 16:04
-1

Assuming the file that contains the filesize was created on the EXACT same machine AND that it was originally written with an off_t type, you can just cast the char[] -> an off_t. eg:

off_t filesize = *((off_t*)str);
user590028
  • 11,364
  • 3
  • 40
  • 57
  • 1
    You probably meant `... = *((off_t *) str);`? – alk Feb 07 '15 at 15:31
  • If you also now would adjust your wording accordingly, this would be a valid answer ... you aren't casting to `off_t` but to `off_t *`. – alk Feb 07 '15 at 15:42