O que é o Bit Masking?

191

Eu sou bastante novo na programação C e encontrei um pouco de mascaramento. Alguém pode me explicar o conceito geral e a função do mascaramento de bits? Exemplos são muito apreciados.

Mr.Z
fonte
1
Você entende operadores bit a bit, como & | ^ etc e lógica booleana em geral? Qualquer explicação das operações da máscara exigirá isso.
Paul R
1
Sim eu tenho um entender de operadores bit a bit e lógica booleana
Mr.Z
2
Eu sei que os links não devem ser publicados, mas a explicação da wikipedia é ótima: pt.wikipedia.org/wiki/Mask_(computing)
pevik:
2
O @pevik está ok para postar o link, mas com alguma descrição, para que, se algum dia o link morrer, o post ainda possa servir ao seu propósito de responder. O link também não deve ser meramente para fins promocionais.
Dexter

Respostas:

246

Uma máscara define quais bits você deseja manter e quais bits você deseja limpar.

Mascarar é o ato de aplicar uma máscara a um valor. Isso é realizado fazendo:

  • AND bit a bit para extrair um subconjunto dos bits no valor
  • OR bit a bit para definir um subconjunto dos bits no valor
  • XOR bit a bit para alternar um subconjunto dos bits no valor

Abaixo está um exemplo de extração de um subconjunto dos bits no valor:

Mask:   00001111b
Value:  01010101b

A aplicação da máscara ao valor significa que queremos limpar os primeiros 4 bits (superiores) e manter os últimos 4 bits (inferiores). Assim, extraímos os 4 bits inferiores. O resultado é:

Mask:   00001111b
Value:  01010101b
Result: 00000101b

O mascaramento é implementado usando AND, portanto, em C, obtemos:

uint8_t stuff(...) {
  uint8_t mask = 0x0f;   // 00001111b
  uint8_t value = 0x55;  // 01010101b
  return mask & value;
}

Aqui está um caso de uso bastante comum: Extraindo bytes individuais de uma palavra maior. Definimos os bits de alta ordem na palavra como o primeiro byte. Usamos dois operadores para isso &, e >>(shift right). É assim que podemos extrair os quatro bytes de um número inteiro de 32 bits:

void more_stuff(uint32_t value) {             // Example value: 0x01020304
    uint32_t byte1 = (value >> 24);           // 0x01020304 >> 24 is 0x01 so
                                              // no masking is necessary
    uint32_t byte2 = (value >> 16) & 0xff;    // 0x01020304 >> 16 is 0x0102 so
                                              // we must mask to get 0x02
    uint32_t byte3 = (value >> 8)  & 0xff;    // 0x01020304 >> 8 is 0x010203 so
                                              // we must mask to get 0x03
    uint32_t byte4 = value & 0xff;            // here we only mask, no shifting
                                              // is necessary
    ...
}

Observe que você pode mudar a ordem dos operadores acima, primeiro pode fazer a máscara e depois o turno. Os resultados são os mesmos, mas agora você teria que usar uma máscara diferente:

uint32_t byte3 = (value & 0xff00) >> 8;
user239558
fonte
5
Uma boa resposta, mas mascaramento, também pode ser aplicada para definir ou alternar bits específicos com operações OR ou XOR e uma máscara adequada.
Paul R
@ user239558 obrigado pelo exemplo e pela sintaxe adequada. @ Paul R. Eu diria simplesmente mask AND value no exemplo fornecido por user239558
Mr.Z 8/12/12
@ Mr.Z: em C, C ++ e linguagens relacionadas, seria o operador AND bit a bit , escrito como &.
Paul R
@ Mr.Z Por exemplo: clara um byte de um uint32_t mascarando o conteúdo longe: #define MASK 0x000000FF .... my_uint32_t &= ~MASK.
Lundin
o bliteral binário para indicar não é suportado por todos os compiladores, correto?
Ungeheuer
76

Mascarar significa manter / alterar / remover uma parte desejada da informação. Vamos ver uma operação de mascaramento de imagens; como esta operação de mascaramento está removendo qualquer coisa que não seja de pele

insira a descrição da imagem aqui

Estamos fazendo E operação neste exemplo. Existem também outros operadores de mascaramento - OU , XOR .


Mascaramento de bits significa impor máscara sobre bits. Aqui está um pouco de mascaramento com AND -

     1 1 1 0 1 1 0 1   [input]
(&)  0 0 1 1 1 1 0 0    [mask]
------------------------------
     0 0 1 0 1 1 0 0  [output]

Portanto, apenas os 4 bits do meio (como esses bits estão 1nessa máscara) permanecem.

Vamos ver isso com o XOR -

     1 1 1 0 1 1 0 1   [input]
(^)  0 0 1 1 1 1 0 0    [mask]
------------------------------
     1 1 0 1 0 0 0 1  [output]

Agora, os 4 bits do meio são invertidos ( 1tornaram-se 0, 0tornaram-se 1).


Assim, usando máscara de bits, podemos acessar bits individuais [ exemplos ]. Às vezes, essa técnica também pode ser usada para melhorar o desempenho. Veja isso por exemplo:

bool isOdd(int i) {
    return i%2;
}

Esta função informa se um número inteiro é ímpar / par. Podemos alcançar o mesmo resultado com mais eficiência usando máscara de bits

bool isOdd(int i) {
    return i&1;
}

Breve explicação : se o bit menos significativo de um número binário for 1, ele será ímpar; por 0isso vai ser mesmo. Então, fazendo AND com 1estamos removendo todos os outros bits, exceto o bit menos significativo, ou seja:

     55  ->  0 0 1 1 0 1 1 1   [input]
(&)   1  ->  0 0 0 0 0 0 0 1    [mask]
---------------------------------------
      1  <-  0 0 0 0 0 0 0 1  [output]
Minhas Kamal
fonte
1
Além disso, para converter um número inteiro em um número ímpar. se for um número par: i = i | 1. Isto vem a calhar quando estamos tentando gerar uma seqüência como 1, 3, 5, ..., 2, 4, 6, ...
Harshit Sharma
Você também pode usar a seguinte operação para encontrar o número apenas com o bit menos significativo de um inteiro: LSB = i & -i
Harshit Sharma