in reply to print behavior

Hi Monks

This behaviour is there with C/C++ "printf" also. We need to know how the "print" statement (see coments below ) is handling variables & its data. Our code in question is

my $x = 0; print $x, $x++; # Print 10??

All the arguments passed to the "print" is kept in a stack! print will push arguments from right-to-left into the stack. Inthe above case value of $x goes into stack (corresponding to $x++).

After the first "push", $x is incremented and on second "push" new value of $x is pushed. Then it start poping to print. For sure it will pop 1 first and then 0. So it will print 10. A program to demo this can be

#!/usr/bin/perl use strict; my @PRINT_STACK; my $x = 0; push @PRINT_STACK, $x++; print "PRINT_STACK => ( ",@PRINT_STACK, " )\n"; push @PRINT_STACK, $x; print "PRINT_STACK =>( ",join(", ",@PRINT_STACK)," )\n"; print pop @PRINT_STACK; print pop @PRINT_STACK; exit();

Again funny facts :)

my $x = 0; print $x,$x, $x++; # Print 110??

This will print 110 for sure, because the value of $x is NOT changed after first push.

Then what would be

my $x = 0; print $x,$x++, $x++; # Print 210??

In case of "C" it will print 210 as expected. but the output you will get in perl is 201. If I make a table with more $x++ in print, it will be as follows (assuming that initial value of $x is 0 ).

Print orderO/P in CO/P in Perl
$x00
$x,$x++1010
$x,$x,$x++110110
$x,$x++,$x++210201
$x,$x++,$x++,$x++32103012
$x,$x++,$x++,$x++,$x++4321040123
$x,$x++,$x++,$x++,$x++,$x++543210501234

"C" is working as I explained above. Why Perl is behaving differently when we have "$x,$x++,$x++" ? Answer is again stacks.

when there are more than one expressions in same statement, perl uses another stack for evaluating them. ie, it wll push 0 to stack first. Then increments $x to 1. Then again it pushes 1 to stack and increments it to 2. Now all operations are over. Now Perl with pop contents of the operation stack and push to print stack. Then push the last $x. So it will print "201" for

print $x,$x++,$x++

Following program will demonstrate the entire thing :)

#!/usr/bin/perl use strict; my @PRINT_STACK; my @OP_STACK; my $x = 0; my $temp; #print $x,$x++,$x++; push @OP_STACK, $x++; # push the l +ast $x++ to the operator stack (pushes 0) print "OP_STACK => ( ",@OP_STACK, " )\n"; push @OP_STACK, $x++; # push the n +ext $x++ operator to the operator stack (pushes 1) print "OP_STACK => ( ",join(", ",@OP_STACK)," )\n"; # All Operations are over $temp = pop @OP_STACK; #pop The ope +rator stack and push it to print stack (pops 1) push @PRINT_STACK, $temp; # pushes 1 print "PRINT_STACK => ( ",join(", ",@PRINT_STACK)," )\n"; $temp = pop @OP_STACK; #pop The ope +rator stack and push it to print stack (pops 0) push @PRINT_STACK, $temp; #pushes 0 print "PRINT_STACK => ( ",join(", ",@PRINT_STACK)," )\n"; push @PRINT_STACK, $x; # push the f +irst $x to the operator stack (pushes 2) print "PRINT_STACK => ( ",join(", ",@PRINT_STACK)," )\n"; print pop @PRINT_STACK; print pop @PRINT_STACK; print pop @PRINT_STACK; exit();

Isn't this a nice hack for obfuscation ?

Comments

Cheers!

--VC

UPDATE : I am not sure about all C compilers. I got above behavior with "gcc on FC6 & Turbo C on Windows XP". Also for Perl I tested with "Active Perl On Windows XP & Perl on FC6". I was NOT trying to say Perl & C will behave alike, but I was trying to say that this IS there with most of the implementation of C (gcc on FC6 and turbo C on Windows XP) & Perl (Active Perl On Win XP and perl on FC6). SORRY if misleading.

Replies are listed 'Best First'.
Re^2: print behavior
by ikegami (Patriarch) on Jul 10, 2007 at 16:57 UTC

    You're making the mistake of assuming Perl and C will behave the same on all systems. Statements like "This will print 110 for sure" and "In case of 'C' it will print 210 as expected." are wrong. The order in which the args are evaluated is not defined in either language. That's why it's harmful to modify a variable in a parameter list expression when the variable appears elsewhere in that parameter list.

      I am not sure about all C compilers. I got above behavior with "gcc on FC6 & Turbo C on Windows XP". Also for Perl I tested with "Active Perl On Windows XP & Perl on FC6". I was NOT trying to say Perl & C will behave alike, but I was trying to say that this IS there with most of the implementation of C (gcc on FC6 and turbo C on Windows XP) & Perl (Active Perl On Win XP and perl on FC6). SORRY if misleading.


      Obfuscation is NOT the only measure of expertise.

Re^2: print behavior
by polettix (Vicar) on Jul 11, 2007 at 11:34 UTC
    Why do you update your post instead of answering to ikegami's reply? This makes it rather difficult to follow the discussion.

    Also, a note about the undefined order of execution. The fact that some compilers seem to behave in a certain manner does not mean that you can rely on it. It means that they can change their mind whenever they want, without notice, and it's simply plain wrong to rely on it.

    This said, it can probably be useful only in some golfing competition, where you can be sure that a certain version of perl (with the lowercase "p") on a certain architecture will be used, and you can thus take advantage of any implementation decision, feature or bug this perl exhibits. Usage in obfuscation is weaker, IMHO, because it could behave differently across different versions or architectures.

    Flavio
    perl -ple'$_=reverse' <<<ti.xittelop@oivalf

    Don't fool yourself.