40

Trying to answer to another post whose solution deals with IP addresses and netmasks, I got stuck with plain bitwise arithmetic.

Is there a standard way, in Python, to carry on bitwise AND, OR, XOR, NOT operations assuming that the inputs are "32 bit" (maybe negative) integers or longs, and that the result must be a long in the range [0, 2**32]?

In other words, I need a working Python counterpart to the C bitwise operations between unsigned longs.

EDIT: the specific issue is this:

>>> m = 0xFFFFFF00   # netmask 255.255.255.0
>>> ~m
-4294967041L         # wtf?! I want 255
Federico A. Ramponi
  • 46,145
  • 29
  • 109
  • 133
  • I imagine Pythons loose typing would play hell with any algorithm like this... I want to see one too, just out of curiousity. – Matthew Scharley Oct 16 '08 at 23:40
  • As of Python 3.3, some users encountering this might be interested in [the ipaddress module](http://docs.python.org/dev/library/ipaddress). – gerrit Feb 05 '14 at 09:41

5 Answers5

62

You can use ctypes and its c_uint32:

>>> import ctypes
>>> m = 0xFFFFFF00
>>> ctypes.c_uint32(~m).value
255L

So what I did here was casting ~m to a C 32-bit unsigned integer and retrieving its value back in Python format.

Dzinx
  • 55,586
  • 10
  • 60
  • 78
51

You can mask everything by 0xFFFFFFFF:

>>> m = 0xFFFFFF00
>>> allf = 0xFFFFFFFF
>>> ~m & allf
255L
John Millikin
  • 197,344
  • 39
  • 212
  • 226
  • 1
    This strategy also helps with [bash arithmetic](http://stackoverflow.com/questions/3222379/how-to-efficiently-convert-long-int-to-dotted-quad-ip-in-bash). – bstpierre Mar 02 '11 at 21:53
  • 1
    You're doing one more operation than necessary. ANDing a NOT is the same as an XOR. So, `m ^ allf` is what you need. – HardlyKnowEm Dec 13 '12 at 21:48
  • @mlefavor I don't know where you got the idea that `~a & b` is the same as `a ^ b`. It's not in general. – Ned Batchelder Dec 28 '12 at 17:33
  • I guess that was overexuberant of me. But I think it's true in the case of 0xFFFFFFFF. – HardlyKnowEm Dec 29 '12 at 19:45
  • 1
    See this wiki for the reason for needing the mask: https://wiki.python.org/moin/BitwiseOperators In a nutshell, negative numbers are treated as if they have an infinite number of leading 1s. The bitmask shaves off all but the number of digits that you want. – OozeMeister May 14 '15 at 14:58
12
from numpy import uint32
pixelbeat
  • 30,615
  • 9
  • 51
  • 60
  • @gerrit Is he referring to the fact that it requires the system to have the numpy module installed whereas ctypes is a part of core python? – penguin359 Nov 27 '15 at 18:18
6

You could also xor with 0xFFFFFFFF, which is equivalent to the "unsigned complement".

>>> 0xFFFFFF00 ^ 0xFFFFFFFF
255
Maarten
  • 4,549
  • 4
  • 31
  • 36
1

This is a module that I created a long time ago, and it might be of help to you:

IPv4Utils

It provides at least a CIDR class with subnet arithmetic. Check the test cases at the end of the module for examples.

tzot
  • 92,761
  • 29
  • 141
  • 204