C/C++: Armazenando dois valores na mesma variável

Com o barateamento da memória RAM, hoje em dia ela raramente é a causa de preocupação dos programadores. Não se faz mais esse tipo de coisa, sequer é recomendado, mas a quem interessar, aqui está um jeito de armazenar dois valores na mesma variável.


Usarei um char como exemplo, pois os outros tipos de variáveis não se beneficiam desta técnica. Por exemplo, um int tem sizeof igual a quatro. Caso não sejam necessários esses quatro bytes, é mais simples usar um short int, que tem sizeof dois.

Além disso, por mais estranho que pareça, um char e um int são internamente representados da mesma forma. Creio que a maioria já sabia disso, estava apenas recordando.

Agora a explicação em si de como funciona esta técnica (ou gambiarra, se preferir). Um char tem sizeof igual a um. Isso significa que ele ocupa um byte da sua memória. Como um byte é igual a oito bits, existem 256 (2^8) números que podem ser armazenados em um char. Que números são esses depende do tipo de char com que estamos lidando; um signed char vai de -128 a 127 e um unsigned char vai de 0 a 255.

Digamos que, no entanto, só precisamos armazenar os algarismos de 0 a 9. Oito bits são o dobro do que precisamos para armazenar o número nove. Com três bits teríamos um limite de 2^3-1 (ou seja, 7), insuficiente para o número nove, então precisamos de quatro, tendo assim um limite de 2^4-1 (ou seja, 15).

O que faremos é dividir esse char em duas metades de quatro bits. Chamarei os bits mais baixos de lower e os mais altos de upper. Neste exemplo, a parte upper armazena o número 7; e a lower, o número 6.

0111  | 0110
Upper | Lower

Adquirindo valores

Lower: Para adquirir os valores de lower, basta apagarmos os bits de upper, transformando 0111 0110 em 0000 0110 (6 em binário). Faremos isso usando operadores de bits, neste caso, o operador “E” (representado pelo símbolo &). Ele segue esta tabela:

A | B | A & B
0 0 0
1 0 0
0 1 0
1 1 1

Entretanto, o operador sozinho não faz muita coisa. Precisamos de uma máscara que apague os bits de upper e deixe os bits de lower intactos. A máscara de que precisamos aqui é 0000 1111 (número 15 em binário). De uma maneira ilustrativa, teremos isto:

  0111 0110
& 0000 1111
-----------
  0000 0110

Ou seja, devido ao operador e a máscara, nos livramos da metade do char que não queremos. (getLower)

Upper: Aqui, usar o operador E não nos ajuda muito. Vejamos por que:

  0111 0110
& 1111 0000
-----------
  0111 0000

Ou seja, ao invés do 7 (0111) que queríamos, teremos 112.

Na verdade, este é mais simples. Só precisamos “empurrar” os bits quatro espaços para a direita. Os operadores que fazem isso são “<<” e “>>”. Cada um “empurra” os bits na direção em que aponta n vezes. Na prática, isso significa que o número será multiplicado por 2^n (se for “empurrado” à esquerda) ou dividido por 2^n (se “empurrado” à direita). Ou seja, aqui tanto faz usar “>> 4” ou “/ 16”. Deixei o primeiro mesmo por ser semanticamente mais significativo, mas o resultado é o mesmo. (getUpper)

Atribuindo valores

Para atribuir o valor a uma determinada área do char, primeiro zeramos aquela parte, usando novamente o operador & e uma máscara. Depois é só somar o valor que queremos.

O único “problema” é com o upper. Assim como precisamos “empurrar” os bits quatro vezes à direita na hora de adquirir o valor, agora teremos de “empurrá-los” quatro vezes à esquerda.

#include
#include

#define UPPER 240 /* 1111 0000 */
#define LOWER 15 /* 0000 1111 */

#define getUpper(x) (x >> 4)
#define getLower(x) (x & LOWER)
#define setUpper(x,y) ((x & LOWER) + (y << 4)) #define setLower(x,y) ((x & UPPER) + y) int main(int argc, char* argv[]) { unsigned char test = 0; test = setUpper(test,5); test = setLower(test,7); printf("Lower:%u, Upper:%u\n", getLower(test), getUpper(test)); return(0); } [/sourcecode]

Publicidade

2 Respostas para “C/C++: Armazenando dois valores na mesma variável

  1. Davidson fevereiro 22, 2014 às 7:35 pm

    Interessante, inicialmente pensei que você usaria shifts para aproveitar a parte alta e baixa do char, desconhecia o setUpper/Lower, :D

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair /  Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair /  Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair /  Alterar )

Conectando a %s

%d blogueiros gostam disto: