Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine
 
PerlMonks  

octal number mysteriously changes after pass to subroutine

by Anonymous Monk
on Feb 01, 2023 at 18:56 UTC ( [id://11150073]=perlquestion: print w/replies, xml ) Need Help??

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

Dear Monks, I'm passing an octal file mode to a sub like sub(0666) but in the sub I'm seeing it as 438, and 0777 becomes 511. Quoting the mode causes it to lose the leading zero so that sub(q(0666)) becomes 666. I can put the leading 0 back and continue but that feels messy. Why is 0666 changing to 438? Thank you!
  • Comment on octal number mysteriously changes after pass to subroutine

Replies are listed 'Best First'.
Re: octal number mysteriously changes after pass to subroutine
by pryrt (Abbot) on Feb 01, 2023 at 19:04 UTC
    octal 0666 is equivalent to decimal 438.

    octal 0777 is equivalent to decimal 511.

    When you call fn(0666) , perl interprets 0666 as a number, and stores it as the integer value in the function @_ array. If you print $_[0]; then you will see the integer value in the default decimal representation; if you want to see the number as an octal, format it, like with printf "%#o", $_[0];

    If you pass this value to a chmod using chmod(0666) or chmod($_[0]) then it will be properly interpreted as the right mode.

    If you want to pass it as a string instead (your q(0666) example), then you can extract the underlying value (as shown in the chmod documentation) as chmod(oct(q(0666))) or chmod(oct($_[0])) .

      Thank you pryrt++

      Here's another conundrum, why don't these behave the same:

      perl -le '$n=0666; print $n'
      438
      perl -le '$n=shift; print $n' 0666
      0666

        The one embedded in the source code is an octal number string literal to Perl. The other is a string to Perl, as it comes from @ARGV.

        If you want to treat incoming parameters as octal, see the oct function.

        Updated: s/number string/number literal/, suggested by LanX

        There are fundamental things in Perl, which might be confusing here

        1. a scalar variable can be a number or a string (or a reference ...)
        2. There are various literal notations in code
        3. literals like "txt" , 'txt' , q(txt) , ... will produce the same string txt
        4. literals like 016 , 0xE , 14 will produce the same number (well integer) 14
        5. a string might look like a literal notation of a number like "016" , but literal notation inside strings will not be interpreted
        6. an implicit string to number conversion will always be decimal, hence "016" + 3  == 19 not 17
        7. if you want another base, you need to convert the string explicitly by yourself
        8. one (dangerous) way is eval("016") == 14

        I hope it's clearer now.

        Cheers Rolf
        (addicted to the 𐍀𐌴𐍂𐌻 Programming Language :)
        Wikisyntax for the Monastery

        Arguments are received as strings. The second is equivalent to

        perl -le '$n="0666"; print $n'
        and
        perl -le '$n=q(0666); print $n'
Re: octal number mysteriously changes after pass to subroutine
by ikegami (Patriarch) on Feb 01, 2023 at 21:05 UTC

    The Perl code 0666 produces the number four hundred and thirty-eight, which is 666 in octal and 438 in decimal.

    Four hundred and thirty-eight is the correct value to pass to the chmod builtin to get rw-rw-rw-.

    The Perl code 0777 produces the number five hundred and eleven, which is 777 in octal and 511 in decimal.

    Five hundred and eleven is the correct value to pass to the chmod builtin to get rwxrwxrwx.


    Quoting the mode causes it to lose the leading zero so that sub(q(0666)) becomes 666

    The Perl code q(0666) produces the four-character string 0666.

    If you were to treat that string as a number (e.g. 0+q(0666)) it would get converted in to the number six hundred and sixty-six. When Perl numifies strings, leading zeros do not have a special significance.

    Six hundred and sixty-six is NOT the correct value to pass to the chmod builtin to get rw-rw-rw-.


    If you want to print those numbers in octal, you can use sprintf "%o", $n.

    $ perl -Mv5.14 -e'say sprintf "%o", $_ for 0666, 0777;' 666 777

    Feel free to add a leading zero if you so desire.

    $ perl -Mv5.14 -e'say sprintf "0%o", $_ for 0666, 0777;' 0666 0777
      Thanks again Monks. As you already know, oct solved the problem. Finally fixed that four year old bug. 🐸

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://11150073]
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others pondering the Monastery: (4)
As of 2024-04-26 00:01 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found