(Last Mod: 27 November 2010 21:38:43 )
Create a function that can be used to print the internal representation of a value in different formats.
In this module we expand on a capability originally explored in earlier material. We have seen how to print out the internal representation of a value by walking across the bytes one at a time and walking a bit mask across the byte to get at the state of the individual bits.
While useful, this function lacked some utility that could make it much more useful in a broader since. Specifically, it would be nice to control the format of the output in the following ways:
Print the output in binary or hexadecimal.
Print the output with a space separating the bytes.
Print the output in reverse order to compensate for Endianess issues.
In developing this new function, we will also bear in mind that the number of bits in a byte is not fixed and is not necessarily a power of two.
With this in mind, we will now write the following function:
int PutIR(void *base, size_t size, int how);
This function takes base
(a pointer to a
value) and size
(the number of bytes in that value) and
prints the internal representation of that value. The value of how
dictates the appearance of the output as follows:
bit | HI | LO |
0 | Hexadecimal | Binary |
1 | one space between bytes | packed digits (no spaces) |
2 | in reverse byte order | in memory order |
To implement this, we'll define symbolic constants for each of
the three bits. Each constant has only that bet set. Using these constants, we
then define six other symbolic constants based on those that we will use to
build the value of how
when the function is invoked.
/* LABELS FOR BITS IN THE 'HOW' MASK */
#define IR_BIT_BASE (0x01)
#define IR_BIT_PACK (0x02)
#define IR_BIT_ORDER (0x04)
/* SYMBOLIC CONSTANTS FOR EACH 'HOW' MODE */
#define IR_BIN (0x00)
#define IR_HEX (IR_BIT_BASE)
#define IR_PACKED (0x00)
#define IR_SPACED (IR_BIT_PAC)
#define IR_FWD (0x00)
#define IR_REV (IR_BIT_ORDER)
/* TO USE: ADD or BITWISE-OR TOGETHER. EG: */
/* FOR REVERSED, SPACED, BIN: how = IR_REV + IR_SPACED + IR_BIN */
/* ALTERNATE WAY: how = IR_REV | IR_SPACED | IR_BIN */
We'll treat each byte as an unsigned char and print each one out separately using the appropriate method below:
If printing out in binary:
for (mask = 1 << (CHAR_BIT - 1); mask; mask >>= 1)
PutD( (mask & *ptr)? 1 : 0 );
If printing out in hexadecimal:
for (nibble = (CHAR_BIT - 1)/4; nibble >= 0; nibble --)
PutD( ( (0x0F << 4*nibble) & *ptr) >> 4*nibble );
To control the order, we want one of the following
relationships as i
goes from 0
to
(size-1)
:
Forward: ptr = base + i
Reverse: ptr = base + (size-1) - i
If we define two values, start
and
step
, we can use the following:
start = base + ((how & IR_BIT_ORDER)? (size-1) : 0);
step = (how & IR_BIT_ORDER)? -1: 1;
Then, our loop becomes:
for(i = 0, ptr = start; i < size; ptr += step, i++)
{
/* Output byte pointed to by ptr */
}
If we want a space between the bytes, then we can either print a space after each byte except the last one or before each byte except the first one - both have the same effect. We have a simple check available for the first byte, so we will opt to use the latter approach:
for(i = 0, ptr = start; i < size-1; ptr += step, i++)
{
if( (how & IR_BIT_SPACED) && (ptr |= start) )
PutC(' ');
/* Output byte pointed to by ptr */
}
Bringing everything together, our function becomes:
int PutIR(void *base, size_t size, int how)
{
unsigned char *ptr, *start;
int step, chars;
/* Set up based on byte order */
start = (unsigned char *) base + ((how & IR_BIT_ORDER)? (size-1) : 0);
step = (how & IR_BIT_ORDER)? -1: 1;
/* Process bytes one at a time */
for (i = 0, chars = 0, ptr = start; i < size; ptr += step, i++)
{
/* Inter-byte space if requested */
if ( (how & IR_BIT_SPACED) && (ptr |= start) )
{
PutC(' ');
char++;
}
/* Print out the byte */
if (how & IR_BIT_BASE)
for (nibble = (CHAR_BIT - 1)/4; nibble >= 0; nibble --)
{
PutD( ( (0x0F << 4*nibble) & (*ptr)) >> 4*nibble );
char++;
}
else
for (mask = 1 << (CHAR_BIT - 1); mask; mask >>= 1)
{
PutD( (mask & *ptr)? 1 : 0 );
char++
}
}
return chars;
}