What is an intuitive way to interpret bitwise operators and mask? Also, what is camouflage used for?

I learned about bitwise operators and disguises right now in the class of my computer systems. However, I have some problems with their internalization.

I understand that the operators &, |, ^, → (both arithmetic and logical shifts) and <DO, but I don’t quite understand what they really use, in addition to optimizing the operations of multiplication and division (for → and <<), and to check whether certain bits are turned on or off (operator and operator).

In addition, I do not understand what masking is used for. I know that the execution of x and 0xFF is used to extract the least significant bit to an integer x, but I can not extrapolate it to other types of masks (for example, those that extract the leftmost 1 in the number, which get the number 1s in the number and t .d.)?

Can anyone shed some light on this, preferably with some examples? Thanks.

+1
source share
2 answers

A good way to understand bitmasks is an example, so I will give it. Let's say we have an array of structures:

struct my_struct {
  int foo;
  int bar;
};

struct my_struct array_of_structs[64]; // I picked 64 for a specific reason I will discuss later

, , . - used .

struct my_struct {
  int foo;
  int bar;
  char used;
};

- . 64, 64- . , , , , .

 unsigned long long bitmap;  // Guaranteed to be at least 64 bits (if I recall correctly)

, , 0 , , 1 . i :

bitmap = bitmap | (1ULL << i);

:

bitmap |= (1ULL << i);

(1ULL << i) , 0, i - , bitmap | (1ULL << i) bitmap, , i th ( , ), bitmap |= (1ULL << i);, , i th 1 , . i - , i th , - i - .

, , i , &:

if(bitmap & (1ULL << i)) {
  // i is used
}
else {
  // i is not used
}

bitmap & (1ULL << i) , , , i th bitmap.

, , :

bitmap = bitmap & ~(1ULL << i);

bitmap &= ~(1ULL << i);

~(1ULL << i) 64 ( , unsigned long long - 64 ) , 1, i th . bitmap, , bitmap, , i th 0.

, bitmap vs a used. , , , , , - . , , , , - . , , . , , , , . , .

. . , , .

struct player {
  // some members
  unsigned long long flag;
};

, , , , . , .

#define PLAYER_JUMPING  (1ULL << 0)
#define PLAYER_SWIMMING (1ULL << 1)
#define PLAYER_RUNNING  (1ULL << 2)
#define PLAYER_DEAD     (1ULL << 3)

, .

struct player my_player;
my_player.flag |= PLAYER_JUMPING; // Mark the player as jumping
my_player.flag &= ~PLAYER_SWIMMING; // Mark the player as not swimming
if(my_player.flag & PLAYER_RUNNING)  // Test if the player is running

, , , : ^. .

my_player.flag = my_player.flag ^ PLAYER_DEAD; // If player was dead now player is not dead and vise versa

, :

my_player.flag ^= PLAYER_DEAD; // If player was dead now player is not dead and vise versa

, , , .. x ^ 0 == x .

. , , , :

if(my_player.flag & (PLAYER_RUNNING | PLAYER_JUMPING))  // Test if the player is running or jumping

, (PLAYER_RUNNING | PLAYER_JUMPING) , , , .

+6

, . . ? , ? , ... - - , . , , , , , .

unsigned integer, 4-bytes (, , 4 x86). 0xff, int. , :

ui = 73289  (00000000-00000001-00011110-01001001)

byte0 =  ui & 0xff;    //  0xff = binary 11111111  (255)

byte0 :  73  (01001001)

, mask 0xff - , 255, 11111111, , anded ui 8 ( ) ui.

, 0xff, , , . bitmask. ( , , , , ).

, esm:

#define PLAYER_JUMPING  (1U << 0)
#define PLAYER_SWIMMING (1U << 1)
#define PLAYER_RUNNING  (1U << 2)
#define PLAYER_DEAD     (1U << 3)

, , - :

if ((player[x] & (PLAYER_RUNNING | PLAYER_JUMPING)) == 
    (PLAYER_RUNNING | PLAYER_JUMPING))
    printf ("player[x] is running & jumping");

, , PLAYER_RUNNING | PLAYER_JUMPING ( bitmask) . :

mask_rj = PLAYER_RUNNING | PLAYER_JUMPING;  // its value is '5' or (00000101)

if ((player[x] | mask_rj) == mask_rj)
    printf ("player[x] is running & jumping");

, , :

#include <stdio.h>
#include <limits.h>  // for CHAR_BIT

#if defined(__LP64__) || defined(_LP64)
# define BUILD_64   1
#endif

#ifdef BUILD_64
# define BITS_PER_LONG 64
#else
# define BITS_PER_LONG 32
#endif

#define PLAYER_JUMPING  (1U << 0)
#define PLAYER_SWIMMING (1U << 1)
#define PLAYER_RUNNING  (1U << 2)
#define PLAYER_DEAD     (1U << 3)

char *binpad (unsigned long n, size_t sz);
char *binsep (unsigned long n, size_t sz, unsigned char szs, char sep);

int main (void) {

    unsigned char players[] = { 0b00001000, 0b00000010,
                                0b00000101, 0b00000100 };
    unsigned char nplayers = sizeof players/sizeof *players;
    unsigned char mask_rj = PLAYER_RUNNING | PLAYER_JUMPING;
    unsigned char i = 0;

    printf ("\n  mask_rj    : %hhu  (%s)\n\n", 
            mask_rj, binpad (mask_rj, sizeof mask_rj * CHAR_BIT));

    for (i = 0; i < nplayers; i++)
        printf ("  player [%hhu] : %hhu  (%s)\n", 
                i, players[i], 
                binpad (players[i], sizeof players[i] * CHAR_BIT));

    for (i = 0; i < nplayers; i++)
        if ((players[i] & mask_rj) == mask_rj)
            printf ("\n  player [%hhu] is Running & Jumping\n", i);

    return 0;
}

char *binpad (unsigned long n, size_t sz)
{
    static char s[BITS_PER_LONG + 1] = {0};
    char *p = s + BITS_PER_LONG;
    register size_t i;

    for (i = 0; i < sz; i++)
        *(--p) = (n>>i & 1) ? '1' : '0';

    return p;
}

$ ./bin/bitmask

  mask_rj    : 5  (00000101)

  player [0] : 8  (00001000)
  player [1] : 2  (00000010)
  player [2] : 5  (00000101)
  player [3] : 4  (00000100)

  player [2] is Running & Jumping
+1

Source: https://habr.com/ru/post/1626716/


All Articles