Barcode
Barcode

Reputation: 15

C - Copying nibbles from one byte to another to generate a bitshift by 4

While I know how to copy one bit from one byte to another (as explained here: Link), I have a problem for a full 4 bit shift from one byte to another byte from a different array (especially for up to 106 bytes).

I read here, how to shift two nibbles at once (for a single byte) and I also tried to implement it:

  char *input = (char *)malloc(sizeof(int));
  char gen_message[strlen(input) + 1];
  for(int loop = (strlen(input) - 1); loop >= 0; loop--)
  {
    ((gen_message[(loop + 1)]) & 0xF0) = ((*input[loop]) & 0x0F);
    ((gen_message[loop]) & 0x0F) = ((*input[loop]) & 0xF0);
  }
  gen_message[0] & 0xF0 = 0x4;

Note: Input can between 1 and up to 106 symbols, hence the malloc.

However, I get an error (invalid type of argument of unary '*') and even then I'm not sure if it would be correct.

Can anybody point to a solution or can explain where my brainfart lies, so that I can fix it? Thanks in advance!

-Greetings

Upvotes: 0

Views: 1481

Answers (1)

Brendan
Brendan

Reputation: 37212

Normally (ignoring bitfields) C can't store anything smaller than a char. To work around that you can read the whole char, modify a portion of it, then store the whole (modified) char.

Note that in C char may be signed (e.g. maybe a signed octet with range -128 to +127); and this makes it messy to modify due to uncertainty (e.g. behaviour of "right shift of signed integer" isn't defined). For that reason I'd strongly recommend using unsigned char or uint8_t.

To write the lowest nibble you'd want to do something like:

    dest = dest & 0xF0;        // Clear all bits in the low nibble
    dest = dest | new_nibble;  // Set new bits in the low nibble

To write the highest nibble you'd want to do something like:

    dest = dest & 0x0F;               // Clear all bits in the high nibble
    dest = dest | (new_nibble << 4);  // Set new bits in the high nibble

To read nibbles you'd do something like:

    low_nibble = src & 0x0F;
    high_nibble = (src & 0xF0) >> 4;

Copying is just reading and then writing. For example, to copy the lowest nibble from src to the highest nibble in dest you could:

    nibble = src & 0x0F;
    dest = dest & 0x0F;             // Clear all bits in the high nibble
    dest = dest | (nibble << 4);    // Set new bits in the high nibble

With elements of arrays it might look like this:

    nibble1 = input[loop] & 0x0F;
    nibble2 = (input[loop] & 0xF0) >> 4;
    gen_message[loop + 1] = gen_message[loop + 1] & 0xF0;
    gen_message[loop + 1] = gen_message[loop + 1] | nibble1;
    gen_message[loop] = gen_message[loop] & 0x0F;
    gen_message[loop] = gen_message[loop] | (nibble2 << 4);

This can also be done more concisely:

    gen_message[loop + 1] &= 0xF0;
    gen_message[loop + 1] |= input[loop] & 0x0F;
    gen_message[loop] &= 0x0F;
    gen_message[loop] |= ((input[loop] & 0xF0) >> 4) << 4;

Of course if know that the destination contains zeros already (e.g. due to memset() or calloc()), you can skip the "clear nibble" parts:

    gen_message[loop + 1] |= input[loop] & 0x0F;
    gen_message[loop] |= ((input[loop] & 0xF0) >> 4) << 4;

EDIT

The other commentors are right - due to the number of problems it's hard to guess what you're actually trying to do. I think that you might (but might not) be trying to do something like this:

unsigned char *shiftArray4Bits( unsigned char *srcArray ) {
    int srcLen = strlen(srcArray);
    unsigned char temp = 0;
    unsigned char *destArray;

    destArray = malloc(srcLen + 1);
    if(destArray == NULL) {
        return NULL;     // Failed to allocate memory
    }

    for(int i = 0; i < srcLen; i++) {
        dest[i] = temp | ((srcArray[i] & 0xF0) >> 4);
        temp = (srcArray[i] & 0x0F) << 4;
    }
    dest[i] = temp;
    return dest;
}

Upvotes: 2

Related Questions