ngiordano has asked for the wisdom of the Perl Monks concerning the following question:

Can someone explain to me what a bitwise shift is supposed to return and why?

Its not clear to me why:

8 << 0 = 8

8 << 8 = 2048

8 << 16 = 524288

8 << 24 = 134217728

8 << 32 = 8 <--------------- ???

I would expect 8 << 32 = 0;

I am working with IP address netmasks and I need to convert "/8" or "/16" into a working mask of "255.0.0.0" and "255.255.0.0".

255.255.255.255 << (32 - <cidr val>) gives me a valid mask except where the cidr val equals 32.

Replies are listed 'Best First'.
Re: behavior of bitwise shift
by Fletch (Chancellor) on Oct 25, 2004 at 14:40 UTC

    Not directly an answer, but check out Net::Netmask which already handles this for you.

      just a quic hack how subnets can be translated without using a module
      my $cidr = 8; my $mask = "1" x ( 32 - $cidr ) . "0" x $cidr; print $mask, "\n"; $mask = join ".", ( unpack "C4", ( pack "B*", $mask ) ); print $mask, "\n"

      i also suggest Net::Subnets for working with subnets if it does what you want, in particular matching ip's against subnets is very fast.
        I think you'll need to change
        my $mask = "1" x ( 32 - $cidr ) . "0" x $cidr;
        to
        my $mask = "1" x $cidr . "0" x ( 32 - $cidr );
        since /8 means a mask of 255.0.0.0 and not 255.255.255.0 which is /24.
        But thanks a lot for this example - I was wondering how do that without a module (and could not figure how bitwise shifting should help).
Re: behavior of bitwise shift
by xorl (Deacon) on Oct 25, 2004 at 15:38 UTC
    This site might help you understand the bitwise shift. I agree with the others that there is a better way for you to do whatever it is you want.
Re: behavior of bitwise shift
by Taulmarill (Deacon) on Oct 25, 2004 at 14:38 UTC
    perl seems to use a 32bit integer on your machine (i have a 64bit SPARC and perl uses 32bit too, is this standat or would i just have to conifgure my gcc in a proper way?). now perl bitshift is not shifting to nirvana but looping, so the binary one is shifting to the left (or right, depends on how you look at binarys) reaches the end and then starts from the beginning (lowest value bit).

      That's right, the underlying c is 32 bit, and Perl simply uses c <<. It is said in perlop that:

      "The result of overflowing the range of the integers is undefined because it is undefined also in C. In other words, using 32-bit integers, 1 << 32 is undefined. Shifting by a negative number of bits is also undefined."
Re: behavior of bitwise shift
by Roy Johnson (Monsignor) on Oct 25, 2004 at 14:41 UTC
    It looks like this shift operators automatically mod their operand by the size of an integer for you (and for me). However, that depends on the implementation. From perldoc perlop:
    Note that both "<<" and ">>" in Perl are implemented directly using "<<" and ">>" in C. If "use integer" (see "Integer Arithmetic") is in force then signed C integers are used, else unsigned C integers are used. Either way, the implementation isn't going to generate results larger than the size of the integer type Perl was built with (32 bits or 64 bits).

    The result of overflowing the range of the integers is undefined because it is undefined also in C. In other words, using 32-bit integers, "1 << 32" is undefined. Shifting by a negative number of bits is also undefined.


    Caution: Contents may have been coded under pressure.
Re: behavior of bitwise shift
by hardburn (Abbot) on Oct 25, 2004 at 14:47 UTC

    Not sure how the this is behaving, but I get the same answers in C:

    #include <stdio.h> int main(int argc, char **argv) { int a; printf( "Int size: %d\n", sizeof( a ) ); printf( "8 << 0 == %d\n", 8 << 0 ); printf( "8 << 8 == %d\n", 8 << 8 ); printf( "8 << 16 == %d\n", 8 << 16 ); printf( "8 << 24 == %d\n", 8 << 24 ); /* With this line in, gcc gives me: "test.c:12: warning: left shift count >= width of type" */ /* printf( "8 << 32 == %d\n", 8 << 32 ); */ return 0; }

    Output:

    Int size: 4 8 << 0 == 8 8 << 8 == 2048 8 << 16 == 524288 8 << 24 == 134217728

    "There is no shame in being self-taught, only in not trying to learn in the first place." -- Atrus, Myst: The Book of D'ni.

      "but I get the same answers in C:"

      That's for sure, as Perl's << does nothing more than simply calling c's <<. The behavior was expected. For 32 bit c, the result for 8 << 32 is undefined.

Re: behavior of bitwise shift
by revdiablo (Prior) on Oct 25, 2004 at 21:00 UTC
    Can someone explain to me what a bitwise shift is supposed to return and why?

    I'm not sure if this question has been answered already by the other fine posts, but this helped me understand what was going on:

    for (0 .. 16) { my $shifted = 255 << $_; my $bitstring = unpack "b*", pack "i", $shifted; printf "%2d %8d %s\n", $_, $shifted, $bitstring; }

    The output looks like this:

     0      255 11111111000000000000000000000000
     1      510 01111111100000000000000000000000
     2     1020 00111111110000000000000000000000
     3     2040 00011111111000000000000000000000
     4     4080 00001111111100000000000000000000
     5     8160 00000111111110000000000000000000
     6    16320 00000011111111000000000000000000
     7    32640 00000001111111100000000000000000
     8    65280 00000000111111110000000000000000
     9   130560 00000000011111111000000000000000
    10   261120 00000000001111111100000000000000
    11   522240 00000000000111111110000000000000
    12  1044480 00000000000011111111000000000000
    13  2088960 00000000000001111111100000000000
    14  4177920 00000000000000111111110000000000
    15  8355840 00000000000000011111111000000000
    16 16711680 00000000000000001111111100000000
    

    This clearly shows what's going on. The bits of the original number are being shifted a certain number of times, hence it's called a "bitwise shift operator."