# [Tutor] print IP address range to stdout

Alan Plum alan.plum at uni-koeln.de
Tue Dec 22 13:02:49 CET 2009

```Hi again,

On Di, 2009-12-22 at 12:46 +0100, Alan Plum wrote:
> # Now generate the addresses:
> for ip in range(start, end+1):
>     blocks = []
>     for i in range(4):
>         blocks.append((ip & (0xff << (8 * i))) >> (8 * i))
>     print '.'.join(blocks)

I just realised this gives you the blocks in reverse order. You probably
want to use prepend() rather than append() -- or just use reversed()
before you print.

Also note that there's probably a better way to create the actual blocks
from the integer, but this should suffice.

If you're not familiar with the bitwise operators: the double brackets
are shift operators (left shift and right shift respectively) and shift
the value by a number of bits (`8 * i for i in range(4)`, i.e. `for j in
[0,8,16,24]`). The ampersand is a bitwise AND which "switches off" all
bits other than the ones you select (in this case 0xff, i.e. one block
of 8 bits).

By combining them you first define the bits you want (0xff shifted by i
bits to the left, i.e. [0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000].
Then you apply the mask to the integer, switching off all the bits that
are not part of the block you want. Then you shift the result back (i.e.
to the right) the number of bits you shifted the mask to the left,
leaving the exact block value (otherwise your block value would be off
by several orders of hexadecimal magnitude, i.e. 256 (256^1) for the
second (counting from the right), 256*256 (256^2) for the third and
256*256*256 (256^3) for the fourth.

Also, range() takes endpoints to be exclusive, which is why you iterate
over range(start, end+1) rather than range(start, end). Provided you
want it to behave that way.

Cheers,

Alan Plum

```