0

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

Barcode
  • 15
  • 6
  • 1
    `input` is a pointer, but `input[loop]` is a char. Just get rid of the `*` – stark Dec 22 '18 at 20:37
  • 1
    on the second line `strlen(input)` but the string pointed by _input_ is not initialized – bruno Dec 22 '18 at 20:39
  • 1
    `gen_message[0] & 0xF0 = 0x4;` gives a compiler error: *left operand must be l-value* and on other lines too. – Weather Vane Dec 22 '18 at 20:40
  • What do you expect `strlen(input)` to be the measure of? You don't write anything to `input` after allocating it, so it's not a string, and nothing about how you use it suggests that you even mean it to be a string. Then you proceed to try to dereference its (still uninitialized) elements (`char`s) as though they were pointers? Did you omit some code that actually puts the input in `input`? – Arkku Dec 22 '18 at 20:41
  • @WeatherVane same for `((gen_message[(loop + 1)]) & 0xF0) =` and `((gen_message[loop]) & 0x0F)` – bruno Dec 22 '18 at 20:42
  • @bruno just noticed anyway thanks. – Weather Vane Dec 22 '18 at 20:42
  • 3
    There is something fundamentally wrong with every single line here (well, except the ones that contain only `{` or `}`), so it's really hard to tell what this is even intended to do. – Arkku Dec 22 '18 at 20:43
  • if input can be up to 106 symbols why is it just using `malloc(sizeof(int))` and not the actual number of expected symbols? Then you wouldn't attempt to perform `strlen(input)` (which as pointed out returns a garbage length). – fdk1342 Dec 22 '18 at 21:07

1 Answers1

2

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;
}
Brendan
  • 35,656
  • 2
  • 39
  • 66