Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

Pack number to unsigned short

by BrianP (Acolyte)
on Aug 15, 2015 at 04:47 UTC ( [id://1138668]=perlquestion: print w/replies, xml ) Need Help??

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

I have been trying for an hour to pack a simple number into a type 'S' I have a small number < 10 and need to smash it into a unit16. I think the Perl "pack()" should take a number < 64k and PACK it into 16 contiguous bits resembling a uint16_t in C. All 5000 attempts to figure out this simple function have failed. What am I doing wrong? In C: unit16_t count; // Tiny, 1 digit integer uint48_t rgb; // Full 48 binary bits from 3, uint16s, r, g and b uint64_t rgbc; // The final data, just like RGBA memcpy(rgbc+0, rgb, 3*sizeof(uint16_t)); memcpy(rgbc+3, count, 1*sizeof(uint16_t)); // Voila! 4 ushort numbers in a row in RGBC "PACKED" into 64 adjoining + bits Conceptually this is what I want to do: Take 6 bytes of RGB and 2 bytes of count into a PACK them into a 'Q' 6 +4 $rgbc = pack('Q', $rgb, $count); "Pack a quad from 2 variables and store in RGBC" I have a test number, 0x4567 = decimal 17757 I have a 48 bit RGB dragged from a binary .RAW file in a hash key The tiny count is the data value for an RGB key. I want to write an RGBC file with the count appended to the end of the + RGB value so I will have 4, unit16_t values to make a uint64_t RGBC How does one "Pack" a small number into a 16 bit unsigned integer?? ------------------------------ Attempts: Perl: http://perldoc.perl.org/functions/pack.html pack TEMPLATE,LIST The TEMPLATE is a sequence of characters that give the order and type +of values, as follows: S An unsigned short value. $count=17767; # C=0x4567=Dec17757 $c16 = pack("S", $count); # Pack COUNT to @c = pack("S*", $count); # == 0000 printf("Count= dec %d, hex 0x%04hx, c16=0x%04hx, \@c[%d]=%s\n", $count, $count, $c16, scalar @c, join(", ", @c)); printf("c[0]=%d=0x%08x, c[1]=%d=0x%08x\n", $c[0], $c[0],$c[1],$c[1 +]); -> Count= dec 17767, hex 0x4567, c16=0x0000, @c[1]=gE c[0]=0=0x00000000, c[1]=0=0x00000000 and many error/warning messages Unpack? Count= dec 17767, hex 0x4567, c16=0x0000, @c[2]=14129, 13879 c[0]=14129=0x00003731, c[1]=13879=0x00003637 17767 dec = 0b100010101100111 14129 dec = 0b11011100110001 <<< totally random? 13879 dec = 0b11011000110111 The number packs into a single 'S' with a value of 0x0000 But, it also packs into an array of unsigned shorts with weird values c[0]=14129=0x3731, c[1]=13879=0x3637 None of these integers or hex values bears any resemblance to my numbe +r ------------------------------------------ Obviously the wrong approach: Try putting the number in as a text literal, "17757": @c = unpack("S*", "17757"); # == 0000 printf("\@c[%d]=%s\n", scalar @c, join(", ", @c)); printf("c[0]=%d=0x%08x, c[1]=%d=0x%08x\n", $c[0], $c[0],$c[1],$c[1 +]); @c[2]=14129, 13623 c[0]=14129=0x00003731, c[1]=13623=0x00003537 Same -------------------------------------- Try using hex, 0x4567 @c = pack("S*", 0x4567); # == 0000 printf("\@c[%d]=%s\n", scalar @c, join(", ", @c)); printf("c[0]=%d=0x%08x, c[1]=%d=0x%08x\n", $c[0], $c[0],$c[1],$c[1 +]); return(); @c[1]=gE One array value "gE" c[0]=0=0x00000000 Prints as 0 -------------------------------------- Try doing some math on it so it knows its a number @c = pack("S*", $c16=17757*1); # == 0000 printf("\@c[%d]=%s\n", scalar @c, join(", ", @c)); printf("c[0]=%d=0x%08x, c[1]=%d=0x%08x\n", $c[0], $c[0], $c[1], $c +[1]); return(); @c[1]=]E Weird text and zero for decimal and hex c[0]=0=0x00000000 ------------------------------------------ Confusing pack with unpack? I just used unpack to read a binary RAW fi +le. It worked exactly as expected. @c = unpack("S*", "17757"); # == 0000 printf("\@c[%d]=%s\n", scalar @c, join(", ", @c)); printf("c[0]=%d=0x%08x, c[1]=%d=0x%08x\n", $c[0], $c[0], $c[1], $c +[1]); @c[2]=14129, 13623 c[0]=14129=0x00003731, c[1]=13623=0x00003537 ---------------------------------------------- @c = pack("S*", "17757"); # == 0000 printf("\@c[%d]=%s\n", scalar @c, join(", ", @c)); printf("c[0]=%d=0x%08x, c[1]=%d=0x%08x\n", $c[0], $c[0], $c[1], $c +[1]); @c[1]=]E Argument "]E" isn't numeric in printf at C:\bin\bb.pl line 347. Use of uninitialized value in printf at C:\bin\bb.pl line 347. Use of uninitialized value in printf at C:\bin\bb.pl line 347. c[0]=0=0x00000000, c[1]=0=0x00000000 ==================================================== ==================================================== open(IN, "<$file") or die("CCS: ERROR! <Opening '$file': $!\n"); for($ii = 0; $ii < $sr_num; $ii++) { $sr_len = sysread(IN, $buf, $bsize); # SysRead Length $tr_len += $sr_len; # Total Read Length $tr_num++; # Total Read Number while($buf) { $rgb=substr($buf, 0, 6, ''); # Nibble 6 bytes $rgb2c{$rgb}++; } } # End For II loop foreach $rgb (keys %rgb2c) { $count = $rgb2c{$rgb}; # Attempt to take known 6 byte RGB, some psychotic # perl number and smash them together into a QUAD # a uint64 RGBC value just like a standard RGBA $rgbc = pack('Q', $rgb, $count);

Replies are listed 'Best First'.
Re: Pack number to unsigned short (printf)
by tye (Sage) on Aug 15, 2015 at 05:39 UTC

    I have a small number < 10 and need to smash it into a unit16.

    $count=17767; $c16 = pack("S", $count);

    Congratulations, you did it on your first try.

    printf("... c16=0x%04hx ...", ..., $c16, ...;

    What makes you think printf's %x format wants to be given a string containing two bytes representing a packed value? %x wants a number. You know, like 15 or even '15'. %x doesn't magically decode whatever random packed format you throw at it and think "Hey! That might be a number packed in 'S' format. Why don't I interpret it that way in order to get a numeric value that I can then format into hexadecimal? I should!". What made you think it would?

    You can just discard the rest of your hour of work.

    Unpack?

    Here you go:

    $count = unpack("S", $c16);

    - tye        

    A reply falls below the community's threshold of quality. You may see it by logging in.
Re: Pack number to unsigned short
by AnomalousMonk (Archbishop) on Aug 15, 2015 at 14:34 UTC
    and many error/warning messages

    You didn't feel it worthwhile to post (or, apparently, to ponder) | to ponder any of these error/warning messages, but it's sometimes useful to let Perl help you.

    c:\@Work\Perl\monks>perl -le "use warnings; use strict; ;; my $count = 17767; my $c16 = pack('S', $count); printf(qq{Count = dec %d, hex 0x%04x, c16 = 0x%04x \n}, $count, $count, $c16); " Argument "gE" isn't numeric in printf at -e line 1. Count = dec 17767, hex 0x4567, c16 = 0x0000
    The Argument "gE" isn't numeric in printf at ... warning I'm assuming you got should have been a clue that there was a disjunction between the thing you were trying to print as a number and the numeric nature of the thing itself. I'm assuming you already used them, but, in any event, please see warnings and strict.

    It's also possible to gain insight into the structure of a packed string (once you realize it is a string) with a quick, roll-your-own hex dumper:

    c:\@Work\Perl\monks>perl -le "use warnings; use strict; ;; my $count = 17767; printf qq{%d decimal, %x hex \n}, $count, $count; ;; for my $template (qw(S n v N V)) { printf qq{template '$template': }, $template; my $p = pack $template, $count; printf '%02x ', $_ for unpack 'C*', $p; print ''; } " 17767 decimal, 4567 hex template 'S': 67 45 template 'n': 45 67 template 'v': 67 45 template 'N': 00 00 45 67 template 'V': 67 45 00 00
    (I'm sure there are better string hex dumpers avaliable on CPAN.)

    Update: I notice now that you did, in fact, post many of the warning messages, so I've altered my reply accordingly.


    Give a man a fish:  <%-{-{-{-<

Re: Pack number to unsigned short
by Tux (Canon) on Aug 15, 2015 at 15:42 UTC
    A reply falls below the community's threshold of quality. You may see it by logging in.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1138668]
Approved by 1nickt
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others taking refuge in the Monastery: (3)
As of 2024-04-20 03:34 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found