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

Hi, I need to shift 32 bits in perl. Like $t=0xe1; $r=$t<<32; but it is not working since scalar can hold 32 bits ...can u tell me how to make it work??? i want to send this to postmessage($hnd,$msg,0,$r); $r should contain yx position....x-32 bit y 32-bits how to do????

Replies are listed 'Best First'.
Re: left shift problem
by bart (Canon) on Sep 26, 2007 at 11:00 UTC
    Is that postmassage as per the Windows API? Then I think that the parameters should be in a packed structure. Something like
    $r = pack 'VV', $x, $y; # 8 bytes structure
    ("V" for Little-Endian, standard for Windows on Intel)

    Since lParam can only hold a Long value, 32 bits, you probably need to pass a pointer to this 8 bytes structure, to PostMessage. I'm guessing that for this instance, you need to declare the PostMessage function with a "P" parameter, so it passes a pointer, in Win32::API.

Re: left shift problem
by mwah (Hermit) on Sep 26, 2007 at 11:14 UTC
    raq84dec:  it is not working since scalar can hold 32 bit

    Thats not exactly true in perl. A scalar is a "scalar type" where the width is bound by the adress range, so it might have a lot of bits ;-)

    As bart (Re: left shift problem) already mentioned, just pack two 32bit values together by the pack function:

    ... my ($x, $y) = (122, 233); my $r = pack "L2", $y, $x; # pack two DWORDS print $r; # will print nothing useful print "\n", join "\n", unpack "L*", $r; # will print dwords print "\n", join "\n", unpack "C*", $r; # will print bytes ...
    Choose pack template modifiers which give you the
    correct width and the correct byte order for your
    specific problem, on Win32, the V and L should do fine

    Regards
    mwa
Re: left shift problem
by dwm042 (Priest) on Sep 26, 2007 at 15:10 UTC
    Other people have shown you how to pack it. If you have irregular bit margins (shifts of 31, 32, 33), you might want to do the shifts using big integers:

    #!/usr/bin/perl use warnings; use strict; use Math::BigInt; my $num = Math::BigInt->new('0x01'); my $mask1 = Math::BigInt->new('0x0FFFFFFFF')->blsft(32); my $mask2 = Math::BigInt->new('0x0FFFFFFFF'); print "Number : ", $num->as_hex(), "\n"; $num->blsft(32); print "Num shifted : ", $num->as_hex(), "\n"; # # Split result into something that can be packed. # my $highorder = $num->copy()->band($mask1)->brsft(32); my $loworder = $num->copy()->band($mask2); print "High bits : ", $highorder->numify(), "\n"; print "Low bits : ", $loworder->numify(), "\n";
    And the output is:

    C:\Code>perl bigint_shift.pl Number : 0x1 Num shifted : 0x100000000 High bits : 1 Low bits : 0