F
Frederick Gotham
I was intrigued by someone the other day who posted regarding methods of
"mirror-imaging" the bits in a byte. I thought it might be interesting to
write a fully-portable algorithm for mirror-imaging (i.e. reversing) an
entire chunk of memory, and making the algorithm as fast as possible (yes,
I realise it may be faster on some machines than on others, but still, one
can aim for pretty high average efficiency across the board.)
Anyway, here's my latest code, feel free to tamper. I haven't gone through
it with a fine-tooth comb, so it might contain a bug or two. The method it
uses for reversing bits in a byte is based on the code that looked
something like:
| ((unsigned)val & 128) >> 7
| ((unsigned)val & 64) >> 6
Here it is:
#include <assert.h>
#include <stddef.h>
#include <limits.h>
#include <stdio.h>
/* The following macro sets a specified
sole bit index. (It would be better
to perform the assertion using IMAX_BITS
rather than sizeof(unsigned)*CHAR_BIT).
*/
#define ISOLATE_BIT(index) (\
assert((index) < sizeof(unsigned)*CHAR_BIT), \
1U << (index) )
/* The next macro gives us the reversed bit index,
e.g. for 8-Bit bytes:
0 -> 7 4 -> 3
1 -> 6 5 -> 2
2 -> 5 6 -> 1
3 -> 4 7 -> 0
*/
#define REVERSAL_BIT_POSITION(index) (\
assert((index) < CHAR_BIT), \
CHAR_BIT-1 - (index) )
char unsigned ByteReversal(char unsigned val)
{
unsigned index, reversal = 0;
/* Deal with shifting to the left first. */
for(index = 0; index != CHAR_BIT/2; ++index)
{
reversal |= ((unsigned)val & ISOLATE_BIT(index))
<< REVERSAL_BIT_POSITION(index) - index;
}
/* Now deal with shifting to the right. */
for(; index != CHAR_BIT; ++index)
{
reversal |= ((unsigned)val & ISOLATE_BIT(index)) }
return reversal;
}
void ReverseMemory(void *const pv,size_t const quantity_bytes)
{
int const assert_dummy = (assert(!!pv),0);
char unsigned *p = pv,
*q = p + (quantity_bytes - 1);
for( ; q > p; ++p, --q)
{
unsigned const temp = ByteReversal(*p);
*p = ByteReversal(*q);
*q = temp;
}
}
int main(void)
{
unsigned arr[64] = {0,1,2,3,4,5,6,7,8,9,
10,11,12,13,14,15,16,17,18,19,
20,21,22,23,24,25,26,27,28,29,
30,31,32,33,34,35,36,37,38,39,
40,41,42,43,44,45,46,47,48,49,
50,51,52,53,54,55,56,57,58,59,
60,61,62,63};
unsigned const *p, *const q = arr + sizeof arr/sizeof*arr;
p = arr;
do printf("%u ",*p++);
while (p!=q);
puts("");
ReverseMemory(arr,sizeof arr);
p = arr;
do printf("%u ",*p++);
while (p!=q);
puts("");
ReverseMemory(arr,sizeof arr);
p = arr;
do printf("%u ",*p++);
while (p!=q);
puts("");
}
"mirror-imaging" the bits in a byte. I thought it might be interesting to
write a fully-portable algorithm for mirror-imaging (i.e. reversing) an
entire chunk of memory, and making the algorithm as fast as possible (yes,
I realise it may be faster on some machines than on others, but still, one
can aim for pretty high average efficiency across the board.)
Anyway, here's my latest code, feel free to tamper. I haven't gone through
it with a fine-tooth comb, so it might contain a bug or two. The method it
uses for reversing bits in a byte is based on the code that looked
something like:
| ((unsigned)val & 128) >> 7
| ((unsigned)val & 64) >> 6
Here it is:
#include <assert.h>
#include <stddef.h>
#include <limits.h>
#include <stdio.h>
/* The following macro sets a specified
sole bit index. (It would be better
to perform the assertion using IMAX_BITS
rather than sizeof(unsigned)*CHAR_BIT).
*/
#define ISOLATE_BIT(index) (\
assert((index) < sizeof(unsigned)*CHAR_BIT), \
1U << (index) )
/* The next macro gives us the reversed bit index,
e.g. for 8-Bit bytes:
0 -> 7 4 -> 3
1 -> 6 5 -> 2
2 -> 5 6 -> 1
3 -> 4 7 -> 0
*/
#define REVERSAL_BIT_POSITION(index) (\
assert((index) < CHAR_BIT), \
CHAR_BIT-1 - (index) )
char unsigned ByteReversal(char unsigned val)
{
unsigned index, reversal = 0;
/* Deal with shifting to the left first. */
for(index = 0; index != CHAR_BIT/2; ++index)
{
reversal |= ((unsigned)val & ISOLATE_BIT(index))
<< REVERSAL_BIT_POSITION(index) - index;
}
/* Now deal with shifting to the right. */
for(; index != CHAR_BIT; ++index)
{
reversal |= ((unsigned)val & ISOLATE_BIT(index)) }
return reversal;
}
void ReverseMemory(void *const pv,size_t const quantity_bytes)
{
int const assert_dummy = (assert(!!pv),0);
char unsigned *p = pv,
*q = p + (quantity_bytes - 1);
for( ; q > p; ++p, --q)
{
unsigned const temp = ByteReversal(*p);
*p = ByteReversal(*q);
*q = temp;
}
}
int main(void)
{
unsigned arr[64] = {0,1,2,3,4,5,6,7,8,9,
10,11,12,13,14,15,16,17,18,19,
20,21,22,23,24,25,26,27,28,29,
30,31,32,33,34,35,36,37,38,39,
40,41,42,43,44,45,46,47,48,49,
50,51,52,53,54,55,56,57,58,59,
60,61,62,63};
unsigned const *p, *const q = arr + sizeof arr/sizeof*arr;
p = arr;
do printf("%u ",*p++);
while (p!=q);
puts("");
ReverseMemory(arr,sizeof arr);
p = arr;
do printf("%u ",*p++);
while (p!=q);
puts("");
ReverseMemory(arr,sizeof arr);
p = arr;
do printf("%u ",*p++);
while (p!=q);
puts("");
}