I declare an array
uint8_t data_buffer[64];
I write into it, and then I need to iterate over it looking at the data it stores. The data is written in groups of two.
Right now I am doing something messy like this
for(int i = 1; i < BUFFER_LEN + 1; i += 2)
{
if(data_buffer[i] == 0xff && data_buffer[i+1] == 0xff)
{
write_led_states(i/2 + 1, OFF);
}
else
{
write_led_states(i/2 + 1, ON);
}
}
But I'd much prefer to be able to read two bytes of data at a time from the buffer so I could do something more like this:
for(int i = 1; i < BUFFER_LEN + 1; i++)
{
if(data_buffer[i] == 0xffff) // where data_buffer is being read two bytes at a time
{
write_led_states(i, OFF);
}
else
{
write_led_states(i, ON);
}
}
Another way of saying what I want to do is to remap the indices so they go from looking like this:
[1][2][3][4][5][6][7][8]
to like this:
[1...][2...][3...][4...]
Is this possible?
Change this:
uint8_t data_buffer[64];
to this:
uint16_t data_buffer[32];
uint_16_t uses 2 bytes (16 bits) per element (and adjust the size to half of 64).
PS: Your code seems to access an array out of bounds, which invokes Undefined Behavior, here:
for(int i = 1; i < BUFFER_LEN + 1; i += 2)
Array indexing starts from 0, so this should start from 0 and the condition should be i < BUFFER_LEN.
However, with my appraoch, you don't need to increment by two, so you simply do a clean for loop, like this:
for(int i = 0; i < BUFFER_LEN; ++i)
Simply use a uint16_t instead, which is 2 bytes per element,
uint16_t data_buffer[32];
be careful with endianness if it can be a problem.
Note: it appears that you don't know that arrays are 0 indexed, so
for (int i = 1; i < BUFFER_LEN + 1; i += 2)
shoul probably be (most likely),
for (int i = 0; i < BUFFER_LEN; i += 2)
And in case you do what I suggest, then each element is 2 bytes so you'd need half the number of elements and of course you would increment i by 1
for (int i = 0; i < BUFFER_LEN; ++i)
You can combine the two uint8_t elements into a single uint16_t by bhtshifting:
for (int i = 1; i < BUFFER_LEN + 1; i += 2) {
uint16_t pair = data_buffer[i] << 8 | data_buffer[i+1];
LEDState newLEDState = (pair == 0xffff) ? OFF : ON; // replace "LEDState" with the proper type
write_led_states(i/2 + 1, newLEDState);
}
Related
I try to send a maximum of 8 bytes of data. The first 4 bytes are always the same and involve defined commands and an address. The last 4 bytes should be variable.
So far I'm using this approach. Unfortunatly I was told to not use any for loops in this case.
// Construct data
local_transmit_buffer[0] = EEPROM_CMD_WREN;
local_transmit_buffer[1] = EEPROM_CMD_WRITE;
local_transmit_buffer[2] = High(MSQ_Buffer.address);
local_transmit_buffer[3] = Low(MSQ_Buffer.address);
uint_fast8_t i = 0;
for(i = 0; i < MSQ_Buffer.byte_lenght || i < 4; i++){ // assign data
local_transmit_buffer[i + 4] = MSQ_Buffer.dataPointer[i];
}
This is some test code I'm trying to solve my problem:
#include <stdio.h>
__UINT_FAST8_TYPE__ local_transmit_buffer[8];
__UINT_FAST8_TYPE__ MSQ_Buffer_data[8];
void print_local(){
for (int i = 0; i < 8; i++)
{
printf("%d ", local_transmit_buffer[i]);
}
printf("\n");
}
void print_msg(){
for (int i = 0; i < 8; i++)
{
printf("%d ", MSQ_Buffer_data[i]);
}
printf("\n");
}
int main(){
// assign all local values to 0
for (int i = 0; i < 8; i++)
{
local_transmit_buffer[i] = 0;
} print_local();
// assign all msg values to 1
for (int i = 0; i < 8; i++)
{
MSQ_Buffer_data[i] = i + 1;
} print_msg();
*(local_transmit_buffer + 3) = (__UINT_FAST32_TYPE__)MSQ_Buffer_data;
printf("\n");
print_local();
return 0;
}
The first loops fills up the local_transmit_buffer with 0's and the MSQ_Buffer with 0,1,2,...
local_transmit_buffer -> 0 0 0 0 0 0 0 0
MSQ_Buffer_data -> 1 2 3 4 5 6 7 8
Now i want to assign the first 4 values of MSQ_Buffer_data to local_transmit_buffer like this:
local_transmit_buffer -> 0 0 0 0 1 2 3 4
Is there another way of solving this problem without using for loops or a bit_field?
Solved:
I used the memcpy function to solve my problem
// uint_fast8_t i = 0;
// for(i = 0; i < MSQ_Buffer.byte_lenght || i < 4; i++){ // assign data
// local_transmit_buffer[i + 4] = MSQ_Buffer.dataPointer[i];
// }
// copy a defined number data from the message to the local buffer to send
memcpy(&local_transmit_buffer[4], &MSQ_Buffer.dataPointer, local_save_data_length);
Either just unroll the loop manually by typing out each line, or simply use memcpy. In this case there's no reason why you need abstraction layers, so I'd write the sanest possible code, which is just manual unrolling (and get rid of icky macros):
uint8_t local_transmit_buffer [8];
...
local_transmit_buffer[0] = EEPROM_CMD_WREN;
local_transmit_buffer[1] = EEPROM_CMD_WRITE;
local_transmit_buffer[2] = (uint8_t) ((MSQ_Buffer.address >> 8) & 0xFFu);
local_transmit_buffer[3] = (uint8_t) (MSQ_Buffer.address & 0xFFu);
local_transmit_buffer[4] = MSQ_Buffer.dataPointer[0];
local_transmit_buffer[5] = MSQ_Buffer.dataPointer[1];
local_transmit_buffer[6] = MSQ_Buffer.dataPointer[2];
local_transmit_buffer[7] = MSQ_Buffer.dataPointer[3];
It is not obvious why you can't use a loop though, this doesn't look like the actual EEPROM programming (where overhead code might cause hiccups), but just preparations for it. Start to question such requirements.
Also note that you should not use __UINT_FAST8_TYPE__ but uint8_t. Never use homebrewed types but always stdint.h. But you should not be using fast types for a RAM buffer used for EEPROM programming, because it cannot be allowed to contain padding, ever. This is a bug.
I've written a small function to format raw data to NDEF and then write it onto a tag.
The main part of the function works without any problems, the only thing that is not working is that it keeps writing 0xFF to the end of the sector instead of 0x00, if it's empty.
CODE:
int write_ndef(FreefareTag tag, uint8_t *data, const uint8_t type, size_t isize) {
uint8_t *ndef_msg;
size_t ndef_msg_len;
int sector_count;
ndef_msg = data;
ndef_msg_len = isize;
uint8_t write_data [4];
printf("Printing raw message :\n");
print_hex(ndef_msg, ndef_msg_len);
size_t encoded_size;
uint8_t *tlv_data = tlv_encode(type, ndef_msg, ndef_msg_len, &encoded_size);
printf("NDEF file is %zu bytes long.\n", encoded_size);
printf("Printing NDEF formatted message :\n");
print_hex(tlv_data, encoded_size);
sector_count = encoded_size / 4;
if((encoded_size%4)!= 0)
sector_count++;
for (size_t i = 0; i < sector_count; i++) {
for (size_t f = 0; f < 4; f++) {
/*once message written fill rest of sector with 0x00*/
if((i * 4 )+ f > encoded_size) {
write_data[f] = 0x00;
}
else {
write_data[f] = tlv_data[(i * 4) + f];
}
}
ntag21x_write(tag, block[i], write_data);/*takes an array with exactly 4 bytes and writes it to given address on given tag*/
}
return 1;
}
The program output is:
It probably has something to do with the way I'm splitting up the data to write it, but I just can't figure out how.
The last (3rd in this case) block of data reads: 0x67, 0x6c, 0xfe, 0xff (instead of 0x00 as it should).
Your test for reaching the end of the encoded data is off by one.
((i * 4) + f) > encoded_size
This is only true starting with the second byte after the end of the TLV encoded data (e.g. if encoded_data == 0, the test would still be false for i = 0, f = 1).
Consequently, you need to modify this condition to
if (((i * 4) + f) >= encoded_size) {
write_data[f] = 0x00;
} else {
write_data[f] = tlv_data[(i * 4) + f];
}
How Can I change objects name by a loop?
I want create a light effect like knight-rider's one. With a PIC
I thought instead of turning on and off manually to use a loop for change RB line number.
I want to change the last number of this Port line name: like RB01 RB02 like this
my code is like this
for(int i = 0; i>6 ; i++ ){
PORTB = 0X00;
RB+i = 1;
}
Are there any kind of method do something like this? thanks
Assuming RB01, RB02, etc are just convenient #defines for accessing the bits in PORTB, you can write the loop with bitwise arithmetic and not use RB0* at all.
for ( int i = 0; i != 6; ++ i ) {
PORTB = 1 << i; /* one light at a time */
/* or */
PORTB = ( 1 << i + 1 ) - 1; /* light all in sequence */
}
It's not very elegant, but one way is to do it like this:
PORTB = 0x00;
for (i = 0; i < 6; ++i)
{
RB00 = (i == 0);
RB01 = (i == 1);
RB02 = (i == 2);
RB03 = (i == 3);
RB04 = (i == 4);
RB05 = (i == 5);
// note: you probably want to put a delay in here, e.g. 200 ms
}
If you want to keep the previous LEDs on each time you turn on a new one then you can do that like this:
PORTB = 0x00;
for (i = 0; i < 6; ++i)
{
RB00 = (i >= 0);
RB01 = (i >= 1);
RB02 = (i >= 2);
RB03 = (i >= 3);
RB04 = (i >= 4);
RB05 = (i >= 5);
// note: you probably want to put a delay in here, e.g. 200 ms
}
No, there is no way to "generate" symbol names that way. You can use bit masks for manipulating the latch register of the port in question.
I would probably use a table:
struct portbits
{
sometype bit; // Not quite sure what "RB0..RB5" actually translate to.
};
struct portbits bits[] =
{
RB00,
RB01,
RB02,
RB03,
RB04,
RB05,
RB06,
RB07,
};
for(i = 0; i < 7; i++)
{
bits[i] = 1;
}
I have a simple (brute-force) recursive solver algorithm that takes lots of time for bigger values of OpxCnt variable. For small values of OpxCnt, no problem, works like a charm. The algorithm gets very slow as the OpxCnt variable gets bigger. This is to be expected but any optimization or a different algorithm ?
My final goal is that :: I want to read all the True values in the map array by
executing some number of read operations that have the minimum operation
cost. This is not the same as minimum number of read operations.
At function completion, There should be no True value unread.
map array is populated by some external function, any member may be 1 or 0.
For example ::
map[4] = 1;
map[8] = 1;
1 read operation having Adr=4,Cnt=5 has the lowest cost (35)
whereas
2 read operations having Adr=4,Cnt=1 & Adr=8,Cnt=1 costs (27+27=54)
#include <string.h>
typedef unsigned int Ui32;
#define cntof(x) (sizeof(x) / sizeof((x)[0]))
#define ZERO(x) do{memset(&(x), 0, sizeof(x));}while(0)
typedef struct _S_MB_oper{
Ui32 Adr;
Ui32 Cnt;
}S_MB_oper;
typedef struct _S_MB_code{
Ui32 OpxCnt;
S_MB_oper OpxLst[20];
Ui32 OpxPay;
}S_MB_code;
char map[65536] = {0};
static int opx_ListOkey(S_MB_code *px_kod, char *pi_map)
{
int cost = 0;
char map[65536];
memcpy(map, pi_map, sizeof(map));
for(Ui32 o = 0; o < px_kod->OpxCnt; o++)
{
for(Ui32 i = 0; i < px_kod->OpxLst[o].Cnt; i++)
{
Ui32 adr = px_kod->OpxLst[o].Adr + i;
// ...
if(adr < cntof(map)){map[adr] = 0x0;}
}
}
for(Ui32 i = 0; i < cntof(map); i++)
{
if(map[i] > 0x0){return -1;}
}
// calculate COST...
for(Ui32 o = 0; o < px_kod->OpxCnt; o++)
{
cost += 12;
cost += 13;
cost += (2 * px_kod->OpxLst[o].Cnt);
}
px_kod->OpxPay = (Ui32)cost; return cost;
}
static int opx_FindNext(char *map, int pi_idx)
{
int i;
if(pi_idx < 0){pi_idx = 0;}
for(i = pi_idx; i < 65536; i++)
{
if(map[i] > 0x0){return i;}
}
return -1;
}
static int opx_FindZero(char *map, int pi_idx)
{
int i;
if(pi_idx < 0){pi_idx = 0;}
for(i = pi_idx; i < 65536; i++)
{
if(map[i] < 0x1){return i;}
}
return -1;
}
static int opx_Resolver(S_MB_code *po_bst, S_MB_code *px_wrk, char *pi_map, Ui32 *px_idx, int _min, int _max)
{
int pay, kmax, kmin = 1;
if(*px_idx >= px_wrk->OpxCnt)
{
return opx_ListOkey(px_wrk, pi_map);
}
_min = opx_FindNext(pi_map, _min);
// ...
if(_min < 0){return -1;}
kmax = (_max - _min) + 1;
// must be less than 127 !
if(kmax > 127){kmax = 127;}
// is this recursion the last one ?
if(*px_idx >= (px_wrk->OpxCnt - 1))
{
kmin = kmax;
}
else
{
int zero = opx_FindZero(pi_map, _min);
// ...
if(zero > 0)
{
kmin = zero - _min;
// enforce kmax limit !?
if(kmin > kmax){kmin = kmax;}
}
}
for(int _cnt = kmin; _cnt <= kmax; _cnt++)
{
px_wrk->OpxLst[*px_idx].Adr = (Ui32)_min;
px_wrk->OpxLst[*px_idx].Cnt = (Ui32)_cnt;
(*px_idx)++;
pay = opx_Resolver(po_bst, px_wrk, pi_map, px_idx, (_min + _cnt), _max);
(*px_idx)--;
if(pay > 0)
{
if((Ui32)pay < po_bst->OpxPay)
{
memcpy(po_bst, px_wrk, sizeof(*po_bst));
}
}
}
return (int)po_bst->OpxPay;
}
int main()
{
int _max = -1, _cnt = 0;
S_MB_code best = {0};
S_MB_code work = {0};
// SOME TEST DATA...
map[ 4] = 1;
map[ 8] = 1;
/*
map[64] = 1;
map[72] = 1;
map[80] = 1;
map[88] = 1;
map[96] = 1;
*/
// SOME TEST DATA...
for(int i = 0; i < cntof(map); i++)
{
if(map[i] > 0)
{
_max = i; _cnt++;
}
}
// num of Opx can be as much as num of individual bit(s).
if(_cnt > cntof(work.OpxLst)){_cnt = cntof(work.OpxLst);}
best.OpxPay = 1000000000L; // invalid great number...
for(int opx_cnt = 1; opx_cnt <= _cnt; opx_cnt++)
{
int rv;
Ui32 x = 0;
ZERO(work); work.OpxCnt = (Ui32)opx_cnt;
rv = opx_Resolver(&best, &work, map, &x, -42, _max);
}
return 0;
}
You can use dynamic programming to calculate the lowest cost that covers the first i true values in map[]. Call this f(i). As I'll explain, you can calculate f(i) by looking at all f(j) for j < i, so this will take time quadratic in the number of true values -- much better than exponential. The final answer you're looking for will be f(n), where n is the number of true values in map[].
A first step is to preprocess map[] into a list of the positions of true values. (It's possible to do DP on the raw map[] array, but this will be slower if true values are sparse, and cannot be faster.)
int pos[65536]; // Every position *could* be true
int nTrue = 0;
void getPosList() {
for (int i = 0; i < 65536; ++i) {
if (map[i]) pos[nTrue++] = i;
}
}
When we're looking at the subproblem on just the first i true values, what we know is that the ith true value must be covered by a read that ends at i. This block could start at any position j <= i; we don't know, so we have to test all i of them and pick the best. The key property (Optimal Substructure) that enables DP here is that in any optimal solution to the i-sized subproblem, if the read that covers the ith true value starts at the jth true value, then the preceding j-1 true values must be covered by an optimal solution to the (j-1)-sized subproblem.
So: f(i) = min(f(j) + score(pos(j+1), pos(i)), with the minimum taken over all 1 <= j < i. pos(k) refers to the position of the kth true value in map[], and score(x, y) is the score of a read from position x to position y, inclusive.
int scores[65537]; // We effectively start indexing at 1
scores[0] = 0; // Covering the first 0 true values requires 0 cost
// Calculate the minimum score that could allow the first i > 0 true values
// to be read, and store it in scores[i].
// We can assume that all lower values have already been calculated.
void calcF(int i) {
int bestStart, bestScore = INT_MAX;
for (int j = 0; j < i; ++j) { // Always executes at least once
int attemptScore = scores[j] + score(pos[j + 1], pos[i]);
if (attemptScore < bestScore) {
bestStart = j + 1;
bestScore = attemptScore;
}
}
scores[i] = bestScore;
}
int score(int i, int j) {
return 25 + 2 * (j + 1 - i);
}
int main(int argc, char **argv) {
// Set up map[] however you want
getPosList();
for (int i = 1; i <= nTrue; ++i) {
calcF(i);
}
printf("Optimal solution has cost %d.\n", scores[nTrue]);
return 0;
}
Extracting a Solution from Scores
Using this scheme, you can calculate the score of an optimal solution: it's simply f(n), where n is the number of true values in map[]. In order to actually construct the solution, you need to read back through the table of f() scores to infer which choice was made:
void printSolution() {
int i = nTrue;
while (i) {
for (int j = 0; j < i; ++j) {
if (scores[i] == scores[j] + score(pos[j + 1], pos[i])) {
// We know that a read can be made from pos[j + 1] to pos[i] in
// an optimal solution, so let's make it.
printf("Read from %d to %d for cost %d.\n", pos[j + 1], pos[i], score(pos[j + 1], pos[i]));
i = j;
break;
}
}
}
}
There may be several possible choices, but all of them will produce optimal solutions.
Further Speedups
The solution above will work for an arbitrary scoring function. Because your scoring function has a simple structure, it may be that even faster algorithms can be developed.
For example, we can prove that there is a gap width above which it is always beneficial to break a single read into two reads. Suppose we have a read from position x-a to x, and another read from position y to y+b, with y > x. The combined costs of these two separate reads are 25 + 2 * (a + 1) + 25 + 2 * (b + 1) = 54 + 2 * (a + b). A single read stretching from x-a to y+b would cost 25 + 2 * (y + b - x + a + 1) = 27 + 2 * (a + b) + 2 * (y - x). Therefore the single read costs 27 - 2 * (y - x) less. If y - x > 13, this difference goes below zero: in other words, it can never be optimal to include a single read that spans a gap of 12 or more.
To make use of this property, inside calcF(), final reads could be tried in decreasing order of start-position (i.e. in increasing order of width), and the inner loop stopped as soon as any gap width exceeds 12. Because that read and all subsequent wider reads tried would contain this too-large gap and therefore be suboptimal, they need not be tried.
I've just started learning C and I'm having some problems with some code I want to write.
Basically I have this struct that is a bit array, with the number of bits in the array, and a pointer to a buffer of chars, that stores the bits.
My strategy for rotating the bit array is simply taking the number of rotations (mod the length to avoid full rotations) and using a simple reversal algorithm to rotate the array.
EDIT:
However, my problem is that I want to rotate the bits in the actual buffer.
I also want to be able to rotate a subsequence of bits within the entire bit array. So for 1101101, I might want to rotate (0-indexed from the left) the subsequence starting at index 2 and ending at index 5. I'm not entirely sure how to use my char buffer to do this.
Thanks for the help!
struct arrayBits{
size_t numBits;
char *buf;
}
The buf array holds 8-bit integers, not bools as I previously mentioned.
The way that I can access and set an individual bit is just by indexing into the byte that holds the bit I want (so for an array ab, ab->buf[index_of_desired_bit/8] and then performing some bitwise operations on it to change the value, for performance reasons.
EDIT: Thanks to everyone for all the suggestions. I've looked at all of them and I believe I understand the code better. Here's the code I ended up writing, however, I think there are some problems with it.
While it passes some of my basic test cases, it seems to run a little too fast on an bitarray of size 98775 bits, randomly filled. By this I mean, is there some case in which my code just outright fails and crashes? The test cases do three rotations, in a row, on the full 98775-bit array. One rotation of -98775/4 (<--this is a size_t, so wrap around?), one rotation of 98775/4, and then a final rotation of 98775/2.
Is there something I'm missing or some problem I'm not seeing?
/*Reverse a bit array*/
/*v1.1: basic bit reversal w/o temp variable*/
static void arrayReversal(bitarray_t *ba, size_t begin, size_t end){
while(begin < end)
{
bitarray_set(ba, begin, (bitarray_get(ba, begin) ^ bitarray_get(ba, end))); /*x = x ^ y*/
bitarray_set(ba, end, (bitarray_get(ba, begin) ^ bitarray_get(ba, end))); /*y = x ^ y*/
bitarray_set(ba, begin, (bitarray_get(ba, begin) ^ bitarray_get(ba, end))); /*x = x ^ y*/
begin++;
end--;
}
}
/*Main Rotation Routine*/
void bitarray_rotate(bitarray_t *ba, size_t bit_off, size_t bit_len, ssize_t bit_right_amount) {
assert(bit_off + bit_len <= ba->bit_sz);
assert(bit_off + bit_len > 0);
if(bit_off + bit_len > ba->bit_sz || bit_off + bit_len < 0)
{
printf("\nError: Indices out of bounds\n");
return;
}
/*Find index to split bitarray on*/
if(bit_len == 0) return; //Rotate only 1 bit i.e. no rotation
size_t reversal_index;
reversal_index = modulo(-bit_right_amount, bit_len);
if(reversal_index == 0) return; //No rotation to do
/*3 bit string reversals*/
assert(reversal_index - 1 + bit_off < ba->bit_sz);
/* Reverse A*/
arrayReversal(ba, bit_off, reversal_index - 1 + bit_off);
assert(reversal_index + bit_off < ba->bit_sz);
/*Reverse B*/
arrayReversal(ba, reversal_index + bit_off, (bit_off + bit_len - 1));
/*Reverse ArBr*/
arrayReversal(ba, bit_off, (bit_off + bit_len -1));
}
Well the easy way to start is to consider how to rotate the bits in a single value. Let's say that you have x, which is an N-bit value and you want to rotate it by k places. (I'm only going to look at rotating upwards/left, it is easy to convert to downwards/right). The first thing to observe is that if k=N then x is unchanged. So before rotating we want to reduce k modulo N to throw away complete rotations.
Next we should observe that during the rotation the k upper-bits will move to the bottom of the value, and the lower N-k bits will move up k places. This is the same as saying that the top k-bits move down N-k places. The reason that we phrase it this way is that C has shift operators, but not rotation.
In psuedo-C we can say:
#define N sizeof(type)*8
type rotate(type x, int k) {
type lower = x & ((1 << (N-k)) - 1);
type upper = x >> (N-k) & ((1 <<k)-1);
return upper | lower;
}
This takes care of the simple atomic case, simply replace type with char or int as appropriate. If type is unsigned then the mask on the value of upper is unnecessary.
The next thing to consider is rotating in an array of values. If you think of the above code as glueing together two halves of a value then for the more complicated case we need to glue together upper and lower parts from different places in the array. If k is small then these places are adjacent in the array, but when k>N we are rotating through more than one intermediate word.
In particular if we are rotating up k places then we are moving bits from k/N words away in the array, and the N bits can span floor(k/N) and ceil(k/N) locations away in the array. Ok, so now we're ready to put it all together. For each word in the array the new upper N-(k mod N) bits will be the lower bits of floor(k/N) words away, and the new lower (k mod N) bits will be the upper bits of ceil(k/N) words away.
In the same psuedo-C (i.e replace type with what you are using) we can say:
#define N sizeof(type)*8
#define ARR_SIZE ...
type rotate(type *x, int k,type *out) {
int r = k % N;
int upperOff = k/N;
int lowerOff = (k+N-1)/N;
for(int i=0; i<ARR_SIZE; i++) {
int lowerPos = (i + ARR_SIZE - lowerOff) % ARR_SIZE
int upperPos = (i + ARR_SIZE - upperOff) % ARR_SIZE
type lower = x[lowerPos] & ((1 << (N-k)) - 1)
type upper = x[upperPos] >> (N-k) & ((1 <<k)-1)
out[i] = upper | lower;
}
}
Anyway, that's a lot more than I was intending to write so I'll quit now. It should be easy enough to convert this to a form that works inplace on a single array, but you'll probably want to fix the types and the range of k first in order to bound the temporary storage.
If you have any more problems in this area then one place to look is bitmap sprite graphics. For example this rotation problem was used to implement scrolling many, many moons ago in 8-bit games.
I would suggest a pointer/offset to a starting point of a bit in the buffer instead of rotating. Feel free to overload any operator that might be useful, operator[] comes to mind.
A rotate(n) would simply be a offset+=n operation. But I find the purpose of your comment about -"However, my problem is that I want to rotate the actual buffer" confusing.
You dont need an extra buffer for rotate (only for output).
You should implement a function for one rotate and loop this, eg: (right-shift variation)
char *itoa2(char *s,size_t i)
{
*s=0;
do {
memmove(s+1,s,strlen(s)+1);
*s='0'+(i&1);
} while( i>>=1 );
return s;
}
size_t bitrotateOne(size_t i)
{
return i>>1 | (i&1) << (sizeof i<<3)-1;
}
...
size_t i=12,num=17;
char b[129];
while( num-- )
{
i = bitrotateOne(i);
puts( itoa2(b,i) );
}
Since your criteria is so complex, I think the easiest way to do it would be to step through each bit and set where it would be in your new array. You could speed it up for some operations by copying a whole character if it is outside the shifted bits, but I can't think of how to reliably do shifting taking into account all the variables because the start and end of the shifted sequence can be in the middle of bytes and so can the end of the entire bits. The key is to get the new bit position for a bit in the old array:
j = (i < startBit || i >= startBit + length) ? i :
((i - startBit + shiftRightCount) % length) + startBit;
Code:
#include "stdafx.h"
#include <stdlib.h>
#include <string.h>
typedef struct {
size_t numBits;
unsigned char *buf;
} ARRAYBITS;
// format is big endian, shiftint left 8 bits will shift all bytes to a lower index
ARRAYBITS rotateBits(ARRAYBITS *pOriginalBits, int startBit, int length, int shiftRightCount);
void setBit(unsigned char *buf, int bit, bool isSet);
bool checkBit(unsigned char *buf, int bit);
ARRAYBITS fromString(char *onesAndZeros);
char *toString(ARRAYBITS *pBits);
int _tmain(int argc, _TCHAR* argv[])
{
char input[1024];
ARRAYBITS bits = fromString("11110000110010101110"); // 20 bits
ARRAYBITS bitsA = rotateBits(&bits, 0, bits.numBits, 1);
ARRAYBITS bitsB = rotateBits(&bits, 0, bits.numBits, -1);
ARRAYBITS bitsC = rotateBits(&bits, 6, 8, 4);
ARRAYBITS bitsD = rotateBits(&bits, 6, 8, -2);
ARRAYBITS bitsE = rotateBits(&bits, 6, 8, 31);
ARRAYBITS bitsF = rotateBits(&bits, 6, 8, -31);
printf("Starting : %s\n", toString(&bits));
printf("All right 1: %s\n", toString(&bitsA));
printf("All left 1 : %s\n", toString(&bitsB));
printf("\n");
printf(" : ********\n");
printf("Starting : %s\n", toString(&bits));
printf("6,8,4 : %s\n", toString(&bitsC));
printf("6,8,-2 : %s\n", toString(&bitsD));
printf("6,8,31 : %s\n", toString(&bitsE));
printf("6,8,-31 : %s\n", toString(&bitsF));
gets(input);
}
ARRAYBITS rotateBits(ARRAYBITS *pOriginalBits, int startBit, int length, int shiftRightCount)
{
// 0-8 == 1, 9-16 == 2, 17-24 == 3
ARRAYBITS newBits;
int i = 0, j = 0;
int bytes = 0;
while (shiftRightCount < 0)
shiftRightCount += length;
shiftRightCount = shiftRightCount % length;
newBits.numBits = pOriginalBits->numBits;
if (pOriginalBits->numBits <= 0)
return newBits;
bytes = ((pOriginalBits->numBits -1) / 8) + 1;
newBits.buf = (unsigned char *)malloc(bytes);
memset(newBits.buf, 0, bytes);
for (i = 0; i < pOriginalBits->numBits; i++) {
j = (i < startBit || i >= startBit + length) ? i : ((i - startBit + shiftRightCount) % length) + startBit;
if (checkBit(pOriginalBits->buf, i))
{
setBit(newBits.buf, j, true);
}
}
return newBits;
}
void setBit(unsigned char *buf, int bit, bool isSet)
{
int charIndex = bit / 8;
unsigned char c = 1 << (bit & 0x07);
if (isSet)
buf[charIndex] |= c;
else
buf[charIndex] &= (c ^ 255);
}
bool checkBit(unsigned char *buf, int bit)
{
// address of char is (bit / 8), bit within char is (bit & 7)
int index = bit / 8;
int b = bit & 7;
int value = 1 << b;
return ((buf[index] & value) > 0);
}
ARRAYBITS fromString(char *onesAndZeros)
{
int i;
ARRAYBITS bits;
int charCount;
bits.numBits = strlen(onesAndZeros);
charCount = ((bits.numBits -1) / 8) + 1;
bits.buf = (unsigned char *)malloc(charCount);
memset(bits.buf, 0, charCount);
for (i = 0; i < bits.numBits; i++)
{
if (onesAndZeros[i] != '0')
setBit(bits.buf, i, true);
}
return bits;
}
char *toString(ARRAYBITS *pBits)
{
char *buf = (char *)malloc(pBits->numBits + 1);
int i;
for (i = 0; i < pBits->numBits; i++)
{
buf[i] = checkBit(pBits->buf, i) ? '1' : '0';
}
buf[i] = 0;
return buf;
}
I suggest you use bit-level operations (>>,<<,~,&,|) rather than wasting space using int. Even so, using an int array, to rotate, pass the left & right index of substring:
void rotate ( struct arrayBits a, int left , int right )
{
int i;
int first_bit;
if(*( a.buf + right ) == 1) first_bit = 1;
else first_bit = 0;
for( i = left+1 ; i <= right ; i++ )
{
*( a.buf + i )=*( a.buf + i - 1 );
}
*a.buf = first_bit;
}
Example:
If struct_array is 010101,
rotate (struct_array,0,5); => rotates whole string 1 int to right
o/p: 101010
rotate (struct_array,2,4); => rotates substring 1 int to right
o/p: 01 001 1
To reverse the bit array call the rotate() function on the substring, size_of_substring times.