Character unpacking

1

I'm having difficulty in the following exercise

  

Using the right shift operator, the AND operator on bits, and a mask, write a function called uncompressingCharacters that receives the integer   unsigned and unzip it into two characters from an unsigned integer, combine the unsigned integer with the 65280 mask (00000000 00000000 11111111 00000000) and shift the result in bits to the right. Assign the resulting value to a char. Then, merge the unsigned integer with the 255 mask (00000000 00000000 00000000 11111111). Assign the result to another char variable.   The program should print the integer unsigned in bits before it is uncompressed and then print the characters in bits to confirm that they have been uncompressed correctly.   :

The first character I can unpack, but the second one does not have the correct value (it is the same as the first uncompressed character).

Next I put the functions that I am using to try to solve the exercise

#include <stdio.h>
#include <stdlib.h>

void compactaCaracteres(char a,char b);
void descompactaCaracteres(unsigned valor);
void mostrarBits(unsigned valor);

int main(void){
   char var1,var2;

   printf("Digite um caractere:");
   scanf("%c",&var1);

   setbuf(stdin,NULL);

   printf("Digite um caractere:");
   scanf("%c",&var2);

   compactaCaracteres(var1,var2);
   return 0;
 }


 void compactaCaracteres(char a,char b){
   unsigned compacta = a;
   compacta <<= 8;
   compacta |= b;
   descompactaCaracteres(compacta);
}


 void descompactaCaracteres(unsigned valor){
   mostrarBits(valor);

   valor &= 65280;
   valor >>= 8;

   char a = valor;
   mostrarBits(a);

   char b = valor & 255;
   mostrarBits(b);
}

// Função utilizada para imprimir os bits

void mostrarBits(unsigned valor){
  unsigned contador;
  unsigned mascara = 1 << 31;

  printf("%10u = ",valor);

  for(contador = 1 ; contador <= 32; contador++){
    putchar(valor & mascara ? '1' : '0');
    valor <<= 1;

    if(contador % 8 == 0){
        putchar(' ');
    }
  }

  putchar('\n');
}
    
asked by anonymous 03.09.2018 / 14:48

1 answer

2

The problem is that at the beginning of decompression the value is lost in the first and binary that is done:

void descompactaCaracteres(unsigned valor){
    mostrarBits(valor);

    valor &= 65280; // aqui
    valor >>= 8;

When you do valor &= 65280 or even valor = valor & 65280; you get only the second block of 8 bits and the rightmost block is lost.

The correct way to do decompression would be to just get the result of and without modifying the valor , like this:

void descompactaCaracteres(unsigned valor) {
    mostrarBits(valor);

    char a = (valor & 65280) >> 8; //só obter sem alterar o valor
    mostrarBits(a);

    char b = valor & 255;
    mostrarBits(b);
}

With this change to input a and b it gives you the following output:

Digite um caractere:Digite um caractere:     
     24930 = 00000000 00000000 01100001 01100010 
        97 = 00000000 00000000 00000000 01100001 
        98 = 00000000 00000000 00000000 01100010 

However, I would like to mention that the idea of functions is modularization and reuse. In this sense the compactaCaracteres function should return the compressed value, to allow it to be called anywhere and do whatever it wants with the result:

unsigned compactaCaracteres(char a,char b) {
// ^---
    unsigned compacta = a;
    compacta <<= 8;
    compacta |= b;
    return compacta; //<---
}

And the descompactaCaracteres function must also somehow return the result. As two values to return a simple solution would be to pass two pointers to the values to be returned:

void descompactaCaracteres(unsigned valor, char *a, char *b) {
//                                              ^---------^--descompactados
    *a = (valor & 65280) >> 8;  //alterar o valor de a
    *b = valor & 255; //alterar o valor de b
}

No main would now call this:

int main(void) {
    char var1,var2;

    printf("Digite um caractere:");
    scanf("%c",&var1);

    setbuf(stdin,NULL);

    printf("Digite um caractere:");
    scanf("%c",&var2);

    unsigned compactado = compactaCaracteres(var1, var2); //compactar
    char a, b;
    descompactaCaracteres(compactado, &a, &b); //descompactar
    mostrarBits(a);
    mostrarBits(b);

    return 0;
}

Bitmasks are also very common to use with define to make it easier. So we could also do two that would facilitate. Something like:

#define ULITMOBYTE 255
#define PENULTIMOBYTE 65280

And use in the appropriate places.

    
03.09.2018 / 15:48