0

Is it possible to store data in integer form from 0 to 255 rather than 8-bit characters.Although both are same thing, how can we do it, for example, with write() function? Is it ok to directly cast any integer to char and vice versa? Does something like

{
    int a[1]=213; 
    write((char*)a,1);
} 

and

{
    int a[1]; 
    read((char*)a,1); 
    cout<<a;
}

work to get 213 from the same location in the file? It may work on that computer but is it portable, in other words, is it suitable for cross-platform projects in that way? If I create a file format for each game level(which will store objects' coordinates in the current level's file) using this principle, will it work on other computers/systems/platforms in order to have loaded same level?

Rob K
  • 8,757
  • 2
  • 32
  • 36
  • "integer to char" - yes, "vice versa" - no (due to address alignment). Also, in the first case (the "legal" one) you will have compatibility problem between big-endian and little-endian. – barak manos Aug 07 '14 at 19:40

3 Answers3

2

The code you show would write the first (lowest-address) byte of a[0]'s object representation - which may or may not be the byte with the value 213. The particular object representation of an int is imeplementation defined.

The portable way of writing one byte with the value of 213 would be

unsigned char c = a[0];
write(&c, 1);
Igor Tandetnik
  • 50,461
  • 4
  • 56
  • 85
0

It will work, with some caveats:

  1. Use reinterpret_cast<char*>(x) instead of (char*)x to be explicit that you’re performing a cast that’s ordinarily unsafe.

  2. sizeof(int) varies between platforms, so you may wish to use a fixed-size integer type from <cstdint> such as int32_t.

  3. Endianness can also differ between platforms, so you should be aware of the platform byte order and swap byte orders to a consistent format when writing the file. You can detect endianness at runtime and swap bytes manually, or use htonl and ntohl to convert between host and network (big-endian) byte order.

Also, as a practical matter, I recommend you prefer text-based formats—they’re less compact, but far easier to debug when things go wrong, since you can examine them in any text editor. If you determine that loading and parsing these files is too slow, then consider moving to a binary format.

Community
  • 1
  • 1
Jon Purdy
  • 53,300
  • 8
  • 96
  • 166
0

You have the right idea, but it could use a bit of refinement.

{
    int intToWrite = 213;
    unsigned char byteToWrite = 0;

    if ( intToWrite > 255 || intToWrite < 0 )
    {
        doError();
        return();
    }

    // since your range is 0-255, you really want the low order byte of the int.
    // Just reading the 1st byte may or may not work for your architecture. I
    // prefer to let the compiler handle the conversion via casting.
    byteToWrite = (unsigned char) intToWrite;

    write( &byteToWrite, sizeof(byteToWrite) );
    // you can hard code the size, but I try to be in the habit of using sizeof
    // since it is better when dealing with multibyte types
}

{
    int a = 0;
    unsigned char toRead = 0;

    // just like the write, the byte ordering of the int will depend on your
    // architecture. You could write code to explicitly handle this, but it's
    // easier to let the compiler figure it out via implicit conversions
    read( &toRead, sizeof(toRead) );

    a = toRead;
    cout<<a;
}

If you need to minimize space or otherwise can't afford the extra char sitting around, then it's definitely possible to read/write a particular location in your integer. However, it can need linking in new headers (e.g. using htons/ntons) or annoying (using platform #defines).

Patrick W
  • 317
  • 1
  • 13