[Tutor] I don't quite understand bitwise

Cameron Simpson cs at cskk.id.au
Tue Dec 15 16:59:17 EST 2020


On 15Dec2020 19:11, nathan tech <nathan-tech at hotmail.com> wrote:
>So I'm working on a project that, as part of this project has a 
>function called self.RegisterHotKey9arg1, arg2, arg3)
>
>It's wx python for context, but I don't think that is relevant.
>
>An example of this is:
>self.RegisterHotKey(self.kid6, win32con.MOD_ALT|win32con.MOD_SHIFT, 0x46)
>
>What I wanted to do was make it so that the second argument could be 
>anything. I was sort of treating arg2 as a list, and so I'd do 
>something like:
>
>l=["shift","windows","alt"]
>
>bit=None
>for x in l:
> bit=bit+x+|
>
>So I started to research how the x|y format works and came across 
>bitwise operators which is apparrently what is meant when x|y|z is 
>used.

Yes.

>But to me they look like ints/

They are ints.

So, we normally write integers in base 10, since we're raised learning 
arithmetic that way and the Arabic number system uses 10 digits. So the 
int 13 is the sum of 1*10 +3.

But we store integers in computers in base 2 because the basic storage 
unit (a "bit") can hold one of 2 values. So in base 2 the value 13 it 
composed of 1*8 + 1*4 + 0*2 + 1*1, and is written 1101 (or 0b1101 if 
you're putting that in a Python programme).

So, bitmasks.

Instead if treating a bitmask as something we do arithmetic with, we 
treat a bitmask as a sequence of independent bits, each indicating an 
on/off or true/false status. We aren't _using_ them as "int"s/numbers, 
we're using them as an array of 1/0 values.

They're just _stored_ in an int.

So your RegisterHotKey call has arg2 as 
win32con.MOD_ALT|win32con.MOD_SHIFT is composing such an array. I don't 
know the values of win32con.MOD_ALT etc, but each will normally be some 
power of 2. Supposing we had these powers of 2 named:

    win32con.MOD_ALT     = 0b1000  # an 8
    win32con.MOD_CTRL    = 0b0100  # a 4
    win32con.MOD_FN      = 0b0010  # a 2
    win32con.MOD_SHIFT   = 0b0001  # a 1

The expression win32con.MOD_ALT|win32con.MOD_SHIFT is 0b1000|0b0001.  
Which is 0b1001 - you're just setting particular bits within the value.

Doing another |win32con.MOD_SHIFT just sets 0b0001 again, which changes 
nothing - it is already a 1.

The "|" is pronounced "or" (well, "bitwise or"). And "&" is pronounced 
"and" (well, "bitwise and"). The result of a|b is a 1 if a=1 or b=1. The 
result of a&b is 1 if a=1 and b=1. Each bit is treated independently.

So pretending the values above, win32con.MOD_ALT|win32con.MOD_SHIFT is 
0b1001, which happens to b a 9 if you treat it as a number.

Doing things this way is effectively a compact way of passing around 
combinations of true/false states, something you _might_ do verbosely in 
Python like this:

    RegisterHotKey(self.kid6, mod_alt=True, mod_shift=True, ...)

but it isn't written that way. The underlying reaons are twofold:

- who wants to write "mod_alt=True, mod_shift=True, ..." for this stuff?

- the underlying library will likely be a C or C++ library, and it is 
  routine to collect "flags" (true/false values) together in a bitmask 
  and just pass it around as an int.

Happy to elaborate further if anything is unclear.

Cheers,
Cameron Simpson <cs at cskk.id.au>


More information about the Tutor mailing list