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

While creating a source-constructed hash for looking up IP addresses, I happened upon the documentation of Perl v-notation, which I had seldom or never used before. While various documents suggest v notation for encoding IP addresses, it doesn't seem to work well for values above 127. For example under the Perl debugger,
DB<9> p sprintf "%X",unpack('S',v4.100) 464 DB<10> p sprintf "%X",unpack('S',v4.160) 4C2 DB<11> p sprintf "%X",unpack('S',v4.127) 47F DB<12> p sprintf "%X",unpack('S',v4.128) 4C2
Should the documentation for v notation say something like "this can be used to encode IPv4 addresses as long as they only contain values less than 128"?

Replies are listed 'Best First'.
Re: v notation and IP addresses
by jwkrahn (Abbot) on Jul 11, 2009 at 19:39 UTC

    From perldata:

    Version Strings

    Note: Version Strings (v-strings) have been deprecated. They will be removed in some future release after Perl 5.8.1. The marginal benefits of v-strings were greatly outweighed by the potential for Surprise and Confusion.

    A literal of the form v1.20.300.4000 is parsed as a string composed of characters with the specified ordinals. This form, known as v-strings, provides an alternative, more readable way to construct strings, rather than use the somewhat less readable interpolation form "\x{1}\x{14}\x{12c}\x{fa0}". This is useful for representing Unicode strings, and for comparing version "numbers" using the string comparison operators, cmp, gt, lt etc. If there are two or more dots in the literal, the leading v may be omitted.

        print v9786;              # prints SMILEY, "\x{263a}"
        print v102.111.111;       # prints "foo"
        print 102.111.111;        # same

    Such literals are accepted by both require and use for doing a version check. Note that using the v-strings for IPv4 addresses is not portable unless you also use the inet_aton()/inet_ntoa() routines of the Socket package.

    Note that since Perl 5.8.1 the single-number v-strings (like v65 ) are not v-strings before the => operator (which is usually used to separate a hash key from a hash value), instead they are interpreted as literal strings ('v65'). They were v-strings from Perl 5.6.0 to Perl 5.8.0, but that caused more confusion and breakage than good. Multi-number v-strings like v65.66 and 65.66.67 continue to be v-strings always.

    Version strings are not meant to be used for IP addresses.

      Version strings are not meant to be used for IP addresses.

      In fact, I think they were... Not that you should ever actually use them.

      use strict; use warnings; use Socket; my $perlmonks1 = inet_aton("66.39.54.27"); my $perlmonks2 = v66.39.54.27; print "Holy crap, this really works?\n" if $perlmonks1 eq $perlmonks2;

      And atually, yes, it does work for values higher than 127...

      for my $IP (qw(66.39.54.27 209.197.123.153 208.159.114.4)) { my $perlmonks1 = inet_aton($IP); my $perlmonks2 = eval qq{ v$IP } or die $@; print "Holy crap, this really works ($IP)?\n" if $perlmonks1 eq $p +erlmonks2; }

      -Paul

        How do you morph "Version Strings" into "meant to be used for IP addresses"?

Re: v notation and IP addresses
by ikegami (Patriarch) on Jul 13, 2009 at 19:34 UTC
    You are mistaken in blaming v. This is actually a bug in unpack that was fixed in 5.10.0.
    for ( [ 127, v4.127 ], [ 128, v4.128 ], [ 160, v4.160 ], [ 194, v4.194 ], ) { my ($x, $vstr) = @$_; # Workaround utf8::downgrade(my $vstr_dn = $vstr); printf( "got: %04X " . "workaround: %04X " . "expecting: 04%3\$02X or %3\$02X04\n", unpack('S', $vstr), unpack('S', $vstr_dn), $x, ); }

    < 5.10.0:

    got: 7F04 workaround: 7F04 expecting: 047F or 7F04 got: C204 workaround: 8004 expecting: 0480 or 8004 got: C204 workaround: A004 expecting: 04A0 or A004 got: C304 workaround: C204 expecting: 04C2 or C204

    ≥ 5.10.0:

    got: 7F04 workaround: 7F04 expecting: 047F or 7F04 got: 8004 workaround: 8004 expecting: 0480 or 8004 got: A004 workaround: A004 expecting: 04A0 or A004 got: C204 workaround: C204 expecting: 04C2 or C204

    Before 5.10.0, unpack used the internal buffer of its inputs with no regards to how the string was encoded within that buffer.