F
Frederick Gotham
What do you think of the following code for setting and retrieving the
value of bytes in an unsigned integer? The least significant bit has
index 0, then the next least significant bit has index 1, and so on. The
code computes at runtime the byte-order of the unsigned integer, but alas
it would be better if it could be determined at compile-time. The code
potentially invokes undefined behaviour if an unsigned integer contains
padding bits. Hypothetically, it would be possible to work with an
unsigned integer type which contains padding, so long as the amount of
value representation bits is an exact multiple of CHAR_BIT.
I've written such code before in C++, making use of classes and the
like... but I have to say I found it very enjoyable to write it in C.
I also welcome any nit-picks whatsoever...
#include <stddef.h>
typedef struct ByteIndexes {
size_t indexes[ sizeof(unsigned) ];
} ByteIndexes;
#include <limits.h>
ByteIndexes DetermineIndexes(void)
{
unsigned guinea_pig = 0;
const unsigned char *p = (unsigned char*)&guinea_pig;
const unsigned char * const p_over = (unsigned char*)(&guinea_pig +
1);
ByteIndexes bi;
size_t *p_struct = bi.indexes;
unsigned byte_number = 1;
do guinea_pig |= byte_number << CHAR_BIT * byte_number;
while ( ++byte_number != sizeof(unsigned) );
do *p_struct++ = *p++;
while( p != p_over );
return bi;
}
size_t LSBIndexToByteIndex( size_t const i )
{
static ByteIndexes bi;
static unsigned first_time = 1;
if (first_time) first_time = 0, bi = DetermineIndexes();
return bi.indexes;
}
unsigned char GetByte(const unsigned * const pu, size_t const LSB_index)
{
const unsigned char * const p = (unsigned char*)pu;
return p[ LSBIndexToByteIndex(LSB_index) ];
}
void SetByte(unsigned * const pu,size_t const LSB_index,unsigned char
const val)
{
unsigned char * const p = (unsigned char*)pu;
p[ LSBIndexToByteIndex(LSB_index) ] = val;
}
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
unsigned i;
SetByte( &i, 0, 59 );
SetByte( &i, 1, 58 );
SetByte( &i, 2, 57 );
SetByte( &i, 3, 56 );
printf( "LSB: Byte 0: %u\n"
" Byte 1: %u\n"
" Byte 2: %u\n"
" Byte 3: %u\n\n",
GetByte(&i,0),
GetByte(&i,1),
GetByte(&i,2),
GetByte(&i,3) );
SetByte( &i, 0, 1 );
SetByte( &i, 1, 2 );
SetByte( &i, 2, 3 );
SetByte( &i, 3, 4 );
printf( "LSB: Byte 0: %u\n"
" Byte 1: %u\n"
" Byte 2: %u\n"
" Byte 3: %u\n\n",
GetByte(&i,0),
GetByte(&i,1),
GetByte(&i,2),
GetByte(&i,3) );
SetByte( &i, 0, 9 );
SetByte( &i, 1, 7 );
SetByte( &i, 2, 5 );
SetByte( &i, 3, 3 );
printf( "LSB: Byte 0: %u\n"
" Byte 1: %u\n"
" Byte 2: %u\n"
" Byte 3: %u\n\n",
GetByte(&i,0),
GetByte(&i,1),
GetByte(&i,2),
GetByte(&i,3) );
system( "PAUSE" );
}
value of bytes in an unsigned integer? The least significant bit has
index 0, then the next least significant bit has index 1, and so on. The
code computes at runtime the byte-order of the unsigned integer, but alas
it would be better if it could be determined at compile-time. The code
potentially invokes undefined behaviour if an unsigned integer contains
padding bits. Hypothetically, it would be possible to work with an
unsigned integer type which contains padding, so long as the amount of
value representation bits is an exact multiple of CHAR_BIT.
I've written such code before in C++, making use of classes and the
like... but I have to say I found it very enjoyable to write it in C.
I also welcome any nit-picks whatsoever...
#include <stddef.h>
typedef struct ByteIndexes {
size_t indexes[ sizeof(unsigned) ];
} ByteIndexes;
#include <limits.h>
ByteIndexes DetermineIndexes(void)
{
unsigned guinea_pig = 0;
const unsigned char *p = (unsigned char*)&guinea_pig;
const unsigned char * const p_over = (unsigned char*)(&guinea_pig +
1);
ByteIndexes bi;
size_t *p_struct = bi.indexes;
unsigned byte_number = 1;
do guinea_pig |= byte_number << CHAR_BIT * byte_number;
while ( ++byte_number != sizeof(unsigned) );
do *p_struct++ = *p++;
while( p != p_over );
return bi;
}
size_t LSBIndexToByteIndex( size_t const i )
{
static ByteIndexes bi;
static unsigned first_time = 1;
if (first_time) first_time = 0, bi = DetermineIndexes();
return bi.indexes;
}
unsigned char GetByte(const unsigned * const pu, size_t const LSB_index)
{
const unsigned char * const p = (unsigned char*)pu;
return p[ LSBIndexToByteIndex(LSB_index) ];
}
void SetByte(unsigned * const pu,size_t const LSB_index,unsigned char
const val)
{
unsigned char * const p = (unsigned char*)pu;
p[ LSBIndexToByteIndex(LSB_index) ] = val;
}
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
unsigned i;
SetByte( &i, 0, 59 );
SetByte( &i, 1, 58 );
SetByte( &i, 2, 57 );
SetByte( &i, 3, 56 );
printf( "LSB: Byte 0: %u\n"
" Byte 1: %u\n"
" Byte 2: %u\n"
" Byte 3: %u\n\n",
GetByte(&i,0),
GetByte(&i,1),
GetByte(&i,2),
GetByte(&i,3) );
SetByte( &i, 0, 1 );
SetByte( &i, 1, 2 );
SetByte( &i, 2, 3 );
SetByte( &i, 3, 4 );
printf( "LSB: Byte 0: %u\n"
" Byte 1: %u\n"
" Byte 2: %u\n"
" Byte 3: %u\n\n",
GetByte(&i,0),
GetByte(&i,1),
GetByte(&i,2),
GetByte(&i,3) );
SetByte( &i, 0, 9 );
SetByte( &i, 1, 7 );
SetByte( &i, 2, 5 );
SetByte( &i, 3, 3 );
printf( "LSB: Byte 0: %u\n"
" Byte 1: %u\n"
" Byte 2: %u\n"
" Byte 3: %u\n\n",
GetByte(&i,0),
GetByte(&i,1),
GetByte(&i,2),
GetByte(&i,3) );
system( "PAUSE" );
}