[Tutor] bit shifting
Peter Otten
__peter__ at web.de
Thu May 1 12:38:19 CEST 2014
Ian D wrote:
> I am trying to follow some code. It is basically a python scratch
> interfacing script.
> Anyway part of the script has this code.
> Searching google for >> greater than signs in code with python has its
> issues.
> Can anyone clarify this stuff.
> I know its about 4 bytes of data. It looks like its setting all bits HIGH
> to me?
> n = len(cmd)
> a = array('c')
> a.append(chr((n>> 24) & 0xFF))
> a.append(chr((n>> 16) & 0xFF))
> a.append(chr((n>> 8) & 0xFF))
> a.append(chr(n & 0xFF))
[...]
> scratchSock.send(a.tostring() + cmd)
This is a way to serialize the integer n. The code assumes that it consists
of 32 bits or 4 bytes.
Example: given a cmd that is 2271560481 bytes long the corresponding int n
written in binary is
>>> n = 2271560481
>>> bin(n)
'0b10000111011001010100001100100001'
To extract the highest byte you shift-right 24 bits and get
>>> bin(n>>24)
'0b10000111'
In this case the mask 0xff or 0b11111111 has no effect
>>> bin(n>>24 & 0xff)
'0b10000111'
(or rather it silences the error that commands longer than 2**32 are not
supported) but to get the second highest byte the mask is necessary as
>>> bin(n>>16)
'0b1000011101100101'
gives the 16 highest bits. Let's clip the high bits off:
>>> bin(0b1000011101100101
... & 0b0000000011111111)
'0b1100101' # one leading 0-bit implied
Two more bytes, and we get the string "\x87eC":
>>> import array
>>> a = array.array("c")
>>> n = 0x87654321 # now you see how I picked the number for the example
>>> n
2271560481
>>> a.append(chr(n>>24 & 0xff))
>>> a.append(chr(n>>16 & 0xff))
>>> a.append(chr(n>>8 & 0xff))
>>> a.append(chr(n>>0 & 0xff)) # 'n >> 0' is the same as juse 'n'
>>> a.tostring()
'\x87eC!' # "\x86" is Python's way to to display chr(0x87)
To recognize the pattern underneath this odd assembly of bytes we can encode
it:
>>> a.tostring().encode("hex")
'87654321'
So "e" is the same as "\x65", "C" is "\x43", "!" is "\x21".
By the way, there's a function in the library that does the above:
>>> import struct
>>> struct.pack("!I", 0x87654321)
'\x87eC!'
It also does the right thing when the number is too large, it raises an
exception:
>>> struct.pack("!I", 0x987654321)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
struct.error: 'I' format requires 0 <= number <= 4294967295
More information about the Tutor
mailing list