Working with 8-bit integers as flag masks - c

I have 65 different flags (options) for a custom data structure. Currently it looks like this:
struct CustomDataStruct {
int Something;
unsigned char Flags[9]
};
This way I'm able to store up to 72 flags (7 remaining, just in case I decide to add more). I want to use an individual bit for each flag, so I came up with this:
void SetFlag(struct CustomDataStructure* Struct, int FlagNr) {
// Error checking and other stuff here
int index = FlagNr / 8; array.
Struct->Flags[index] |= 1 << (__________);
}
I've already tried with 1 << (FlagNr % 8) but it's not setting the correct bit. For example, I want to turn on flag ID 23 (starting from zero), so I call SetFlag(structInstance, 23), which correctly determines the index (Flags[2]), but 23 % 8 = 7, and 1 << 7 = 1000 0000 (in binary), instead of the correct value, which should be 0000 0001(turn on last bit of the 3rd uchar of the array, i.e bit no. 24).
Flags must be stored on this array, each bit representing the flag switch. Changing this is not an option.

Bits are typically indexed starting from the least significant (rightmost) bit, since in most contexts that makes more sense. If you want to reverse that, just do 1 << (7 - FlagNr % 8) or 0x80 >> (FlagNr % 8).

Rather than doing a bit shift, an array lookup works easily. FlagNr contains the zero based bit index so a value of 0 is the first bit in the first array element.
void setFlag( struct CustomDataStructure* thing, int FlagNr) {
static uint8_t masks[] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
size_t index = FlagNr % 8;
size_t xndex = FlagNr / 8;
thing->Flags[xndex] |= masks[index];
}

void setFlag( struct CustomDataStructure* foo, int flagIndex ) {
assert( flagIndex >= 0 && flagIndex < 72 ); // Defensive programming!
size_t arrayIndex = flagIndex / 8;
int bitShift = flagIndex % 8;
// If you want reverse (little-endian) bit order then subtract from 7:
bitShift = 7 - bitShift;
// This code is expanded for readability. An optimizing-compiler will still generate fast code:
uint8_t flags = foo->Flags[ arrayIndex ];
flags = flags | ( 1 << bitShift );
foo->Flags[ arrayIndex ] = flags;
}

Related

Extracting specific bits from a 4 byte value into a new variable in C

I'm very new to bit manipulations.
let's suppose I have a 32 bit value myInput4ByteValue.
From this 32 bit value I need to extract the bits 25 ..2
What would be the best approach here?
My Idea is to split them into 3 bytes and copy the values there:
struct myOutput3ByteValue.
{
uint8 FirstPart // Bits 9..2 Least Significant 8 Bits from myInput4ByteValue.
uint8 SecondPart // Bits 17 ..10
uint8 ThirdPart // Bits 25 ..18
}
I started with:
myOutput3ByteValue.FirstPart = (myInput4ByteValue & 0x3FC0) // Here I will the bits 9..2
myOutput3ByteValue.SecondPart = ...? //How to fill the rest?
I'm really not sure if I started correctly.
Suggestions would be helpful.
The reason why I split them into 3 bytes is because I will have an own 3 byte-type at the end with which I have to work with it.
What you've got there wont' quite work. 0x3FC0 is a 16 bit int and you're assigning it to an 8 bit int, so it'll get truncated. You need to bitshift << or >>.
So bits 9..2 are:
FirstPart = (value >> 1); // No need to mask as bits 9+ will be truncated
SecondPart = (value >> 9); // Second set of 8 bits
Let's assume you want to put the extracted bits in a single UINT32 variable. What you need is simply to filter first 26 bits and shift them twice:
uint32 filteredValue = ( myInput4ByteValue & 0x03FFFFFF ) >> 2;
With the same logic, you can extract whatever you need and place them in any set of variable, according to the use you have to do wit the filtered bits.
You might want to define a general function performing the bits extraction:
uint32 filterValue( uint32 inValue, uint8 msb, uint8 lsb )
{
uint32 retValue = inValue;
// Let's just check that input params are ok
if( msb < 32 && lsb <32 && msb >= lsb )
{
retValue = ( inValue & ( 0xFFFFFFFF >> ( 31 - msb ) >> lsb;
}
//else... input value unchanged. It doesn't make sense, but it's just an example..
return retValue;
}
I personally wrote and tested it, and it works. Note: it's just an example! Change it according to your requirements.
myInput4ByteValue & 0x3FFFFFF extracts the last 26 bits (the leftmost bit would be bit 25, as one usually starts counting from the right with bit 0).
(myInput4ByteValue & 0x3FFFFFF) >> 2 shifts bits these two places to the right. This would hold your complete 23 bits.
If, however you want to have everything in 8-bit chunks, you could do:
myOutput3ByteValue.FirstPart = (myInput4ByteValue & 0x7F8) >> 2; // bits 9..2
myOutput3ByteValue.SecondPart = (myInput4ByteValue & 0x7F800) >> 10; // bits 17..10
myOutput3ByteValue.ThirdPart = (myInput4ByteValue & 0x3F80000) >> 18; // bits 25..18
Another approach, which could be much easier to read and maintain, is the use of bitfields. See e.g. http://www.catb.org/esr/structure-packing/#_bitfields .
Depending on whether individual bits or groups of bits have a particular meaning, you can give them their own name. If you align the structure nicely, you can simply copy the 32 bit input upon a variable with such a struct as type.
Just write a separate function that extracts no more than 8 bits starting from a given position from a number of the type uint32_t.
Here is a demonstrative program
#include <stdio.h>
#include <stdint.h>
uint8_t getbits( uint32_t x, unsigned p, unsigned n)
{
const unsigned N = 8;
n %= N + 1;
return ( x >> p ) & ~( ~( uint32_t )0 << n );
}
int main(void)
{
uint32_t x = 0x12345678;
/*0001 0010 0011 0100 0101 0110 0111 1000 */
/* ^^^^^^^^^^ = 0x9E */
struct myOutput3ByteValue
{
uint8_t FirstPart; // Bits 9..2 Least Significant 8 Bits from myInput4ByteValue.
uint8_t SecondPart; // Bits 17 ..10
uint8_t ThirdPart; // Bits 25 ..18
} s =
{
.FirstPart = getbits( x, 2, 8 ),
.SecondPart = getbits( x, 10, 8 ),
.ThirdPart = getbits( x, 18, 8 )
};
printf( "%x, %x, %x\n", s.FirstPart, s.SecondPart, s.ThirdPart );
return 0;
}
Its output is
9e, 15, 8d

Best way to move 8 bits into 8 individual bytes [duplicate]

This question already has answers here:
How to create a byte out of 8 bool values (and vice versa)?
(8 answers)
Closed 3 years ago.
I have a status register with 8 bits. I would like to move each individual bit to a byte for further processing. Seems like it should be easy but every solution I come up with is convoluted. I was thinking about iterating through the bits with a for next loop and dumping them into an array but my solution way too messy.
Here's basically what you're trying to do. It uses bitwise operators and a uint8_t array to make each bit an individual byte:
void bits_to_bytes(uint8_t status, uint8_t bits[8])
{
int ctr;
for( ctr = 0; ctr < 8; ctr++ )
{
bits[ctr] = (status >> ctr) & 1;
}
}
OK, so a little more in-depth:
This code loops through the bits in a byte and then assigns bits[bit_number] to the bit_numberth bit of status.
If you want to reverse the order the bits are stored in, simply change bits[ctr] to bits[(8-1)-ctr].
For a start, you should be using uint8_t for eight-bit bit collections since char is fundamentally non-portable unless you add a lot of extra code for checking its size and signedness.
Something like this should suffice for your needs:
void BitsToBytes(uint8_t bits, uint8_t *bytes) {
for (int i = 0; i < 8; ++i) { // The type has exactly eight bits.
*bytes++ = (bits > 127); // 1 if high bit set, else 0.
bits = (bits & 0x7f) << 1; // Shift left to get next bit.
}
}
:
// Call with:
uint8_t inputBits = 0x42;
uint8_t outputBytes[8];
BitsToBytes(inputBits, outputBytes);
This takes a type with eight bits and a buffer of eight bytes, then places the individual bits into each byte of the array:
MSB LSB
+--------+
inputBits: |abcdefgh|
+--------+
+---+---+---+---+---+---+---+---+
outputBytes: | a | b | c | d | e | f | g | h |
+---+---+---+---+---+---+---+---+
If you want it to go the other way (where the LSB of the input is in element 0 of the array), you can simply change the body of the loop to:
*bytes++ = bits & 1; // 1 if low bit set, else 0.
bits = bits >> 1; // Shift right to get next bit.
You can use a double invocation of the ! operator to squash a zero/non-zero value to zero/one. Using this, the extracted value of bit n in status is !!(status & (1 << n)).
If you only have eight flags you might just create constants for the 8 values of 1 << n (0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80). This works particularly well if your flags all have individual names rather than numbers, so that you might have in a header file somewhere:
#define FLAG_FROB 0x01
#define FLAG_FOO 0x02
#define FLAG_BAR 0x04
#define FLAG_BAZ 0x08
#define FLAG_QUUX 0x10
Then in the code you'd just extract them as
flag_frob = !!(status & FLAG_FROB);
flag_foo = !!(status & FLAG_FOO);
flag_bar = !!(status & FLAG_BAR);
flag_baz = !!(status & FLAG_BAZ);
flag_quux = !!(status & FLAG_QUUX);

Bitwise rotate right of 4-bit value

I'm currently trying to control a stepper motor using simple full steps. This means that I'm currently outputting a sequence of values like this:
1000
0100
0010
0001
I thought an easy way to do this was just take my 4-bit value and after each step, perform a rotate right operation. "Code" obviously isn't following any kind of syntax, it's simply there to illustrate my thoughts:
step = 1000;
//Looping
Motor_Out(step)
//Rotate my step variable right by 1 bit
Rotate_Right(step, 1)
My problem is that there obviously isn't any 4-bit simple data types that I can use for this, and if I use an 8-bit unsigned int I will eventually rotate the 1 off to the MSB, which means the 4-bit value I'm actually interested in, will turn into 0000 for a few steps.
I've read that you can use structs and bit-fields to solve this, but the majority of things I read from this is telling me that it's a very bad idea.
With only 4 possible values you would use a table with 9 elements:
unsigned char table_right[] = { [0x1] = 0x8 , [0x2] = 0x1 , [0x4] = 0x2 , [0x8] = 0x4 };
When you need the next value you simply use the current value as the index:
unsigned char current = 0x4; //value is: 0b0100
unsigned char next = table_right[current]; //returns: 0b0010
assert( next == 0x2 );
Doing this in a loop, will loop through all four possible values.
Conveniently, passing an invalid value, will return a zero, so you can write a get function that also asserts next != 0. You should also assert value < 9 before passing the value to the array.
Just use an int to hold the value. When you do the rotate copy the least significant bit to bit 4 and then shift it right by 1:
int rotate(int value)
{
value |= ((value & 1) << 4); // eg 1001 becomes 11001
value >>= 1; // Now value is 1100
return value;
}
The arithmetic for this is simple enough that it will always be faster than the table approach:
constexpr unsigned rotate_right_4bit ( unsigned value )
{
return ( value >> 1 ) | ( ( value << 3 ) & 15 );
}
This turns into 5 lines of branch-free x86 assembly:
lea eax, [0+rdi*8]
shr edi
and eax, 15
or eax, edi
ret
Or, alternatively, if you actually like to see the indexes {3, 2, 1, 0}, then you can split them up into 2 functions, one that "increments" the index, and the other that actually computes the value:
constexpr unsigned decrement_mod4 ( unsigned index )
{
return ( index - 1 ) & 3;
}
constexpr unsigned project ( unsigned index )
{
return 1u << index;
}
IMO the easiest way is:
const unsigned char steps[ 4 ] = { 0x08, 0x04, 0x02, 0x01 };
int stepsIdx = 0;
...
const unsigned char step = steps[ stepsIdx++ ];
stepsIdx = stepsIdx % ( sizeof( steps ) / sizeof( steps[ 0 ] ) );
you can use 10001000b and mod 10000b
and you can get 01000100b 00100010b 00010001b 10001000b repeat.
for example:
char x = 0x88;
Motor_Out(x & 0xf);
Rotate_Right(step, 1);
if I use an 8-bit unsigned int I will eventually rotate the 1 off to the MSB
So use a shift and reinitialize the bit you want when the value goes to zero. C doesn't have a rotate operation anyway, so you'll have to do at least two shifts. (And I suppose C++ doesn't have rotates either.)
x >>= 1;
if (! x) x = 0x08;
Simple, short to write, and obvious in what it does. Yes, it'll compile into a branch (unless the processor has a conditional move operation), but until you have the profiler output to tell you it's important, you just lost more time thinking about it than those processor cycles will ever amount to.
Use an 8-bit data type (like e.g. uint8_t). Initialize it to zero. Set the bit you want to set in the lower four bits of the byte (e.g. value = 0x08).
For each "rotation" take the LSB (least significant bit) and save it. Shift one step right. Overwrite the fourth bit with the bit you saved.
Something like this:
#include <stdio.h>
#include <stdint.h>
uint8_t rotate_one_right(uint8_t value)
{
unsigned saved_bit = value & 1; // Save the LSB
value >>= 1; // Shift right
value |= saved_bit << 3; // Make the saved bit the nibble MSB
return value;
}
int main(void)
{
uint8_t value = 0x08; // Set the high bit in the low nibble
printf("%02hhx\n", value); // Will print 08
value = rotate_one_right(value);
printf("%02hhx\n", value); // Will print 04
value = rotate_one_right(value);
printf("%02hhx\n", value); // Will print 02
value = rotate_one_right(value);
printf("%02hhx\n", value); // Will print 01
value = rotate_one_right(value);
printf("%02hhx\n", value); // Will print 08 again
return 0;
}
Live demonstration.
I would make an array with the values you need and load the correct value from the array. It will take you 4 bytes, it will be fast, and solve your problems even if you start using a different motor type.
for example:
const char values[4]={1,2,4,8};
int current_value = 0;
....
if(++current_value>=4)current_value=0;
motor = values[current_value];
You only need to output 1, 2, 4, and 8. So you can use a counter to mark which bit to set high.
Motor_Out(8 >> i);
i = (i + 1) & 3;
If you want to drive the motor at half steps, you can use an array to store the numbers you need.
const unsigned char out[] = {0x8, 0xc, 0x4, 0x6, 0x2, 0x3, 0x1, 0x9};
Motor_out(out[i]);
i = (i + 1) & 7;
And you can rotate a 4-bit integer like this.
((i * 0x11) >> 1) & 0xf

How to define and work with an array of bits in C?

I want to create a very large array on which I write '0's and '1's. I'm trying to simulate a physical process called random sequential adsorption, where units of length 2, dimers, are deposited onto an n-dimensional lattice at a random location, without overlapping each other. The process stops when there is no more room left on the lattice for depositing more dimers (lattice is jammed).
Initially I start with a lattice of zeroes, and the dimers are represented by a pair of '1's. As each dimer is deposited, the site on the left of the dimer is blocked, due to the fact that the dimers cannot overlap. So I simulate this process by depositing a triple of '1's on the lattice. I need to repeat the entire simulation a large number of times and then work out the average coverage %.
I've already done this using an array of chars for 1D and 2D lattices. At the moment I'm trying to make the code as efficient as possible, before working on the 3D problem and more complicated generalisations.
This is basically what the code looks like in 1D, simplified:
int main()
{
/* Define lattice */
array = (char*)malloc(N * sizeof(char));
total_c = 0;
/* Carry out RSA multiple times */
for (i = 0; i < 1000; i++)
rand_seq_ads();
/* Calculate average coverage efficiency at jamming */
printf("coverage efficiency = %lf", total_c/1000);
return 0;
}
void rand_seq_ads()
{
/* Initialise array, initial conditions */
memset(a, 0, N * sizeof(char));
available_sites = N;
count = 0;
/* While the lattice still has enough room... */
while(available_sites != 0)
{
/* Generate random site location */
x = rand();
/* Deposit dimer (if site is available) */
if(array[x] == 0)
{
array[x] = 1;
array[x+1] = 1;
count += 1;
available_sites += -2;
}
/* Mark site left of dimer as unavailable (if its empty) */
if(array[x-1] == 0)
{
array[x-1] = 1;
available_sites += -1;
}
}
/* Calculate coverage %, and add to total */
c = count/N
total_c += c;
}
For the actual project I'm doing, it involves not just dimers but trimers, quadrimers, and all sorts of shapes and sizes (for 2D and 3D).
I was hoping that I would be able to work with individual bits instead of bytes, but I've been reading around and as far as I can tell you can only change 1 byte at a time, so either I need to do some complicated indexing or there is a simpler way to do it?
Thanks for your answers
If I am not too late, this page gives awesome explanation with examples.
An array of int can be used to deal with array of bits. Assuming size of int to be 4 bytes, when we talk about an int, we are dealing with 32 bits. Say we have int A[10], means we are working on 10*4*8 = 320 bits and following figure shows it: (each element of array has 4 big blocks, each of which represent a byte and each of the smaller blocks represent a bit)
So, to set the kth bit in array A:
// NOTE: if using "uint8_t A[]" instead of "int A[]" then divide by 8, not 32
void SetBit( int A[], int k )
{
int i = k/32; //gives the corresponding index in the array A
int pos = k%32; //gives the corresponding bit position in A[i]
unsigned int flag = 1; // flag = 0000.....00001
flag = flag << pos; // flag = 0000...010...000 (shifted k positions)
A[i] = A[i] | flag; // Set the bit at the k-th position in A[i]
}
or in the shortened version
void SetBit( int A[], int k )
{
A[k/32] |= 1 << (k%32); // Set the bit at the k-th position in A[i]
}
similarly to clear kth bit:
void ClearBit( int A[], int k )
{
A[k/32] &= ~(1 << (k%32));
}
and to test if the kth bit:
int TestBit( int A[], int k )
{
return ( (A[k/32] & (1 << (k%32) )) != 0 ) ;
}
As said above, these manipulations can be written as macros too:
// Due order of operation wrap 'k' in parentheses in case it
// is passed as an equation, e.g. i + 1, otherwise the first
// part evaluates to "A[i + (1/32)]" not "A[(i + 1)/32]"
#define SetBit(A,k) ( A[(k)/32] |= (1 << ((k)%32)) )
#define ClearBit(A,k) ( A[(k)/32] &= ~(1 << ((k)%32)) )
#define TestBit(A,k) ( A[(k)/32] & (1 << ((k)%32)) )
typedef unsigned long bfield_t[ size_needed/sizeof(long) ];
// long because that's probably what your cpu is best at
// The size_needed should be evenly divisable by sizeof(long) or
// you could (sizeof(long)-1+size_needed)/sizeof(long) to force it to round up
Now, each long in a bfield_t can hold sizeof(long)*8 bits.
You can calculate the index of a needed big by:
bindex = index / (8 * sizeof(long) );
and your bit number by
b = index % (8 * sizeof(long) );
You can then look up the long you need and then mask out the bit you need from it.
result = my_field[bindex] & (1<<b);
or
result = 1 & (my_field[bindex]>>b); // if you prefer them to be in bit0
The first one may be faster on some cpus or may save you shifting back up of you need
to perform operations between the same bit in multiple bit arrays. It also mirrors
the setting and clearing of a bit in the field more closely than the second implemention.
set:
my_field[bindex] |= 1<<b;
clear:
my_field[bindex] &= ~(1<<b);
You should remember that you can use bitwise operations on the longs that hold the fields
and that's the same as the operations on the individual bits.
You'll probably also want to look into the ffs, fls, ffc, and flc functions if available. ffs should always be avaiable in strings.h. It's there just for this purpose -- a string of bits.
Anyway, it is find first set and essentially:
int ffs(int x) {
int c = 0;
while (!(x&1) ) {
c++;
x>>=1;
}
return c; // except that it handles x = 0 differently
}
This is a common operation for processors to have an instruction for and your compiler will probably generate that instruction rather than calling a function like the one I wrote. x86 has an instruction for this, by the way. Oh, and ffsl and ffsll are the same function except take long and long long, respectively.
You can use & (bitwise and) and << (left shift).
For example, (1 << 3) results in "00001000" in binary. So your code could look like:
char eightBits = 0;
//Set the 5th and 6th bits from the right to 1
eightBits &= (1 << 4);
eightBits &= (1 << 5);
//eightBits now looks like "00110000".
Then just scale it up with an array of chars and figure out the appropriate byte to modify first.
For more efficiency, you could define a list of bitfields in advance and put them in an array:
#define BIT8 0x01
#define BIT7 0x02
#define BIT6 0x04
#define BIT5 0x08
#define BIT4 0x10
#define BIT3 0x20
#define BIT2 0x40
#define BIT1 0x80
char bits[8] = {BIT1, BIT2, BIT3, BIT4, BIT5, BIT6, BIT7, BIT8};
Then you avoid the overhead of the bit shifting and you can index your bits, turning the previous code into:
eightBits &= (bits[3] & bits[4]);
Alternatively, if you can use C++, you could just use an std::vector<bool> which is internally defined as a vector of bits, complete with direct indexing.
bitarray.h:
#include <inttypes.h> // defines uint32_t
//typedef unsigned int bitarray_t; // if you know that int is 32 bits
typedef uint32_t bitarray_t;
#define RESERVE_BITS(n) (((n)+0x1f)>>5)
#define DW_INDEX(x) ((x)>>5)
#define BIT_INDEX(x) ((x)&0x1f)
#define getbit(array,index) (((array)[DW_INDEX(index)]>>BIT_INDEX(index))&1)
#define putbit(array, index, bit) \
((bit)&1 ? ((array)[DW_INDEX(index)] |= 1<<BIT_INDEX(index)) \
: ((array)[DW_INDEX(index)] &= ~(1<<BIT_INDEX(index))) \
, 0 \
)
Use:
bitarray_t arr[RESERVE_BITS(130)] = {0, 0x12345678,0xabcdef0,0xffff0000,0};
int i = getbit(arr,5);
putbit(arr,6,1);
int x=2; // the least significant bit is 0
putbit(arr,6,x); // sets bit 6 to 0 because 2&1 is 0
putbit(arr,6,!!x); // sets bit 6 to 1 because !!2 is 1
EDIT the docs:
"dword" = "double word" = 32-bit value (unsigned, but that's not really important)
RESERVE_BITS: number_of_bits --> number_of_dwords
RESERVE_BITS(n) is the number of 32-bit integers enough to store n bits
DW_INDEX: bit_index_in_array --> dword_index_in_array
DW_INDEX(i) is the index of dword where the i-th bit is stored.
Both bit and dword indexes start from 0.
BIT_INDEX: bit_index_in_array --> bit_index_in_dword
If i is the number of some bit in the array, BIT_INDEX(i) is the number
of that bit in the dword where the bit is stored.
And the dword is known via DW_INDEX().
getbit: bit_array, bit_index_in_array --> bit_value
putbit: bit_array, bit_index_in_array, bit_value --> 0
getbit(array,i) fetches the dword containing the bit i and shifts the dword right, so that the bit i becomes the least significant bit. Then, a bitwise and with 1 clears all other bits.
putbit(array, i, v) first of all checks the least significant bit of v; if it is 0, we have to clear the bit, and if it is 1, we have to set it.
To set the bit, we do a bitwise or of the dword that contains the bit and the value of 1 shifted left by bit_index_in_dword: that bit is set, and other bits do not change.
To clear the bit, we do a bitwise and of the dword that contains the bit and the bitwise complement of 1 shifted left by bit_index_in_dword: that value has all bits set to one except the only zero bit in the position that we want to clear.
The macro ends with , 0 because otherwise it would return the value of dword where the bit i is stored, and that value is not meaningful. One could also use ((void)0).
It's a trade-off:
(1) use 1 byte for each 2 bit value - simple, fast, but uses 4x memory
(2) pack bits into bytes - more complex, some performance overhead, uses minimum memory
If you have enough memory available then go for (1), otherwise consider (2).

How to shift an array of bytes by 12-bits

I want to shift the contents of an array of bytes by 12-bit to the left.
For example, starting with this array of type uint8_t shift[10]:
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0xBC}
I'd like to shift it to the left by 12-bits resulting in:
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAB, 0xC0, 0x00}
Hurray for pointers!
This code works by looking ahead 12 bits for each byte and copying the proper bits forward. 12 bits is the bottom half (nybble) of the next byte and the top half of 2 bytes away.
unsigned char length = 10;
unsigned char data[10] = {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0A,0xBC};
unsigned char *shift = data;
while (shift < data+(length-2)) {
*shift = (*(shift+1)&0x0F)<<4 | (*(shift+2)&0xF0)>>4;
shift++;
}
*(data+length-2) = (*(data+length-1)&0x0F)<<4;
*(data+length-1) = 0x00;
Justin wrote:
#Mike, your solution works, but does not carry.
Well, I'd say a normal shift operation does just that (called overflow), and just lets the extra bits fall off the right or left. It's simple enough to carry if you wanted to - just save the 12 bits before you start to shift. Maybe you want a circular shift, to put the overflowed bits back at the bottom? Maybe you want to realloc the array and make it larger? Return the overflow to the caller? Return a boolean if non-zero data was overflowed? You'd have to define what carry means to you.
unsigned char overflow[2];
*overflow = (*data&0xF0)>>4;
*(overflow+1) = (*data&0x0F)<<4 | (*(data+1)&0xF0)>>4;
while (shift < data+(length-2)) {
/* normal shifting */
}
/* now would be the time to copy it back if you want to carry it somewhere */
*(data+length-2) = (*(data+length-1)&0x0F)<<4 | (*(overflow)&0x0F);
*(data+length-1) = *(overflow+1);
/* You could return a 16-bit carry int,
* but endian-ness makes that look weird
* if you care about the physical layout */
unsigned short carry = *(overflow+1)<<8 | *overflow;
Here's my solution, but even more importantly my approach to solving the problem.
I approached the problem by
drawing the memory cells and drawing arrows from the destination to the source.
made a table showing the above drawing.
labeling each row in the table with the relative byte address.
This showed me the pattern:
let iL be the low nybble (half byte) of a[i]
let iH be the high nybble of a[i]
iH = (i+1)L
iL = (i+2)H
This pattern holds for all bytes.
Translating into C, this means:
a[i] = (iH << 4) OR iL
a[i] = ((a[i+1] & 0x0f) << 4) | ((a[i+2] & 0xf0) >> 4)
We now make three more observations:
since we carry out the assignments left to right, we don't need to store any values in temporary variables.
we will have a special case for the tail: all 12 bits at the end will be zero.
we must avoid reading undefined memory past the array. since we never read more than a[i+2], this only affects the last two bytes
So, we
handle the general case by looping for N-2 bytes and performing the general calculation above
handle the next to last byte by it by setting iH = (i+1)L
handle the last byte by setting it to 0
given a with length N, we get:
for (i = 0; i < N - 2; ++i) {
a[i] = ((a[i+1] & 0x0f) << 4) | ((a[i+2] & 0xf0) >> 4);
}
a[N-2] = (a[N-1) & 0x0f) << 4;
a[N-1] = 0;
And there you have it... the array is shifted left by 12 bits. It could easily be generalized to shifting N bits, noting that there will be M assignment statements where M = number of bits modulo 8, I believe.
The loop could be made more efficient on some machines by translating to pointers
for (p = a, p2=a+N-2; p != p2; ++p) {
*p = ((*(p+1) & 0x0f) << 4) | (((*(p+2) & 0xf0) >> 4);
}
and by using the largest integer data type supported by the CPU.
(I've just typed this in, so now would be a good time for somebody to review the code, especially since bit twiddling is notoriously easy to get wrong.)
Lets make it the best way to shift N bits in the array of 8 bit integers.
N - Total number of bits to shift
F = (N / 8) - Full 8 bit integers shifted
R = (N % 8) - Remaining bits that need to be shifted
I guess from here you would have to find the most optimal way to make use of this data to move around ints in an array. Generic algorithms would be to apply the full integer shifts by starting from the right of the array and moving each integer F indexes. Zero fill the newly empty spaces. Then finally perform an R bit shift on all of the indexes, again starting from the right.
In the case of shifting 0xBC by R bits you can calculate the overflow by doing a bitwise AND, and the shift using the bitshift operator:
// 0xAB shifted 4 bits is:
(0xAB & 0x0F) >> 4 // is the overflow (0x0A)
0xAB << 4 // is the shifted value (0xB0)
Keep in mind that the 4 bits is just a simple mask: 0x0F or just 0b00001111. This is easy to calculate, dynamically build, or you can even use a simple static lookup table.
I hope that is generic enough. I'm not good with C/C++ at all so maybe someone can clean up my syntax or be more specific.
Bonus: If you're crafty with your C you might be able to fudge multiple array indexes into a single 16, 32, or even 64 bit integer and perform the shifts. But that is prabably not very portable and I would recommend against this. Just a possible optimization.
Here a working solution, using temporary variables:
void shift_4bits_left(uint8_t* array, uint16_t size)
{
int i;
uint8_t shifted = 0x00;
uint8_t overflow = (0xF0 & array[0]) >> 4;
for (i = (size - 1); i >= 0; i--)
{
shifted = (array[i] << 4) | overflow;
overflow = (0xF0 & array[i]) >> 4;
array[i] = shifted;
}
}
Call this function 3 times for a 12-bit shift.
Mike's solution maybe faster, due to the use of temporary variables.
The 32 bit version... :-) Handles 1 <= count <= num_words
#include <stdio.h>
unsigned int array[] = {0x12345678,0x9abcdef0,0x12345678,0x9abcdef0,0x66666666};
int main(void) {
int count;
unsigned int *from, *to;
from = &array[0];
to = &array[0];
count = 5;
while (count-- > 1) {
*to++ = (*from<<12) | ((*++from>>20)&0xfff);
};
*to = (*from<<12);
printf("%x\n", array[0]);
printf("%x\n", array[1]);
printf("%x\n", array[2]);
printf("%x\n", array[3]);
printf("%x\n", array[4]);
return 0;
}
#Joseph, notice that the variables are 8 bits wide, while the shift is 12 bits wide. Your solution works only for N <= variable size.
If you can assume your array is a multiple of 4 you can cast the array into an array of uint64_t and then work on that. If it isn't a multiple of 4, you can work in 64-bit chunks on as much as you can and work on the remainder one by one.
This may be a bit more coding, but I think it's more elegant in the end.
There are a couple of edge-cases which make this a neat problem:
the input array might be empty
the last and next-to-last bits need to be treated specially, because they have zero bits shifted into them
Here's a simple solution which loops over the array copying the low-order nibble of the next byte into its high-order nibble, and the high-order nibble of the next-next (+2) byte into its low-order nibble. To save dereferencing the look-ahead pointer twice, it maintains a two-element buffer with the "last" and "next" bytes:
void shl12(uint8_t *v, size_t length) {
if (length == 0) {
return; // nothing to do
}
if (length > 1) {
uint8_t last_byte, next_byte;
next_byte = *(v + 1);
for (size_t i = 0; i + 2 < length; i++, v++) {
last_byte = next_byte;
next_byte = *(v + 2);
*v = ((last_byte & 0x0f) << 4) | (((next_byte) & 0xf0) >> 4);
}
// the next-to-last byte is half-empty
*(v++) = (next_byte & 0x0f) << 4;
}
// the last byte is always empty
*v = 0;
}
Consider the boundary cases, which activate successively more parts of the function:
When length is zero, we bail out without touching memory.
When length is one, we set the one and only element to zero.
When length is two, we set the high-order nibble of the first byte to low-order nibble of the second byte (that is, bits 12-16), and the second byte to zero. We don't activate the loop.
When length is greater than two we hit the loop, shuffling the bytes across the two-element buffer.
If efficiency is your goal, the answer probably depends largely on your machine's architecture. Typically you should maintain the two-element buffer, but handle a machine word (32/64 bit unsigned integer) at a time. If you're shifting a lot of data it will be worthwhile treating the first few bytes as a special case so that you can get your machine word pointers word-aligned. Most CPUs access memory more efficiently if the accesses fall on machine word boundaries. Of course, the trailing bytes have to be handled specially too so you don't touch memory past the end of the array.

Resources