Tuesday, February 23, 2010

Convert long to byte array in C++ or C

This post explains how to convert an unsigned long int into a byte array in C/C++. This post assumes that the datatype unsigned long int uses 4 bytes of internal storage; however the examples can easily be adapted to other built-in datatypes (unsigned short int, unsigned long long int, etc).

The code to convert a 4-byte unsigned long int into a 4-byte array:


unsigned long int longInt = 1234567890;
unsigned char byteArray[4];

// convert from an unsigned long int to a 4-byte array
byteArray[0] = (int)((longInt >> 24) & 0xFF) ;
byteArray[1] = (int)((longInt >> 16) & 0xFF) ;
byteArray[2] = (int)((longInt >> 8) & 0XFF);
byteArray[3] = (int)((longInt & 0XFF));


So what's happening in the above code? We're basically using a combination of bit shifting and bit masking in order to chop up the unsigned long into 4 pieces. Each of these pieces ends up being a value small enough to be stored in the unsigned char array (remember an unsigned char is 1 byte, and capable of holding values 0-255).

The bit shifting "drops" the right-most bytes, and the bit masking serves to convert the "new" right-most byte into a hex value between 0-255.

Note that in the last line of code we didn't need to do any bit shifting; here we're converting the right-most byte of the unsigned long, and therefore don't want to throw it away.

An alternate solution would be to first apply the mask, and then shift:

byteArray[0] = (int)((longInt & 0xFF000000) >> 24 );
byteArray[1] = (int)((longInt & 0x00FF0000) >> 16 );
byteArray[2] = (int)((longInt & 0x0000FF00) >> 8 );
byteArray[3] = (int)((longInt & 0X000000FF));


Next, let's convert the 4-byte array back into an unsigned long int:


unsigned long int anotherLongInt;

anotherLongInt = ( (byteArray[0] << 24)
+ (byteArray[1] << 16)
+ (byteArray[2] << 8)
+ (byteArray[3] ) );


Here we're taking each piece of the byte array, but now shifting the bits to the left, and adding the results. In essence this is taking each value between 0-255 and depending on the position padding the right-side with an appropriate number of zeroes in order to replicate the significance of the individual values before they are summed.

And an alternate solution to accomplish the same:

anotherLongInt = ((unsigned int) byteArray[0]) << 24;
anotherLongInt |= ((unsigned int) byteArray[1]) << 16;
anotherLongInt |= ((unsigned int) byteArray[2]) << 8;
anotherLongInt |= ((unsigned int) byteArray[3]);


And that's it!

Note that additional fortifications are required when these operations are required in portable code. In that case you won't want to make assumptions on the size of the data types and should instead use additional logic to automatically detect the data type sizes at runtime for the platform on which you're running. Otherwise, the above should be fine if you have a homogeneous and controlled environment in which your code will run.

Tuesday, February 16, 2010

Use Cache_Lite without Pear

This post explains how to use Cache_Lite without using Pear.

Sometimes it may be impractical to install Pear packages on the server -- perhaps Pear isn't installed, perhaps you lack administrative rights, etc. Regardless, the steps below should assist you in using Cache_Lite under these circumstances.

  1. Download the 'manual installation' version of Cache_Lite.
  2. Extract this to some location on your local disk. Open a shell and navigate to this location; next we're going to adjust up the extracted files to better mimic the Pear installation.
  3. Rename the top-level directory from Cache_Lite-X.Y.Z to Cache.
  4. Optional -- you are free to remove the docs and test sub-directories if you wish; this will save on disk space.
  5. Now take the Cache directory and all its contents and place them in someplace accessible from your php include path; in my case I chose the quick and dirty approach and put it in $_SERVER['DOCUMENT_ROOT']/include:
  6. [user@localhost:/var/www/web/include/Cache]$ ls -A1
    LICENSE
    Lite
    Lite.php
    TODO

  7. Incorporate Cache_Lite into your PHP pages as described in the documentation, but with the changes listed below. These will insure that Cache_Lite functions adequately in the absence of Pear.

  8. require_once( 'include/Cache/Lite.php' );

    $cache_lifetime = 30; // in seconds
    $cache_id = '1234';
    $cache_options = array( 'cacheDir' => '/tmp/',
    'lifeTime' => $cache_lifetime,
    'pearErrorMode' => CACHE_LITE_ERROR_DIE
    );

    $Cache_Lite = new Cache_Lite( $cache_options );

    if( $data = $Cache_Lite->get( $cache_id ) )
    {
    // data is the JSON connection string
    $returnValue = $data;
    }
    else
    {
    // value is an array of database values (not shown)

    $data = json_encode( $value );

    // cache the JSON-encoded connection string
    $Cache_Lite->save( $data, $cache_id );

    $returnValue = $data;

    }

  9. Notice that we've set the options for Cache_Lite to not use Pear error mode; this line is important as it will otherwise attempt to use the Pear error handler, which can result in a failure to load since it will attempt to include PEAR.php.
  10. Also note the use of the caching mechanism; here we're caching a JSON string created from database entries. Successive loads of this page first check the cache validity, and if valid, returns the existing cached JSON string. If the cache is out of date, the system will then query the database, create the JSON string, then cache it before returning it back to the caller.