http://www.perlmonks.org?node_id=11130974

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

Oh great ones! I have an array containing four integral values, each of which we may assume is less than 256. I wish to combine them into one 32 bit native integer in little-endian format.

The following code does what I want by printing 67305985:

my @array = (1, 2, 3, 4); my $val = 0; for (my $i = 0; $i < 4; $i++) { $val |= $array[$i]<<(8*$i); } printf "%d\n", $val;

which you may convince yourself is correct by running

perl -e 'printf "%d\n", (4<<24)+(3<<16)+(2<<8)+1')

My question is: how can I do this without a loop? I have played around with pack, unpack and join but have not yet found a way.

Many thanks for your time and wisdom.

Replies are listed 'Best First'.
Re: forming a word from an array of its bytes
by jcb (Parson) on Apr 07, 2021 at 22:35 UTC

    Obvious method: unroll the loop: (untested)

    my @array = (1, 2, 3, 4); my $val = ($array[0]) | ($array[1]<< 8) | ($array[2]<<16) | ($array[3] +<<24); printf "%d\n", $val;

    If clarity is less of a concern, try unpack/pack:

    my @array = (1, 2, 3, 4); my $val = unpack 'L', pack 'C4', @array; printf "%d\n", $val;
      Doh! Never thought of combining unpack and pack that way. Works great, many thanks.

        The simple way to understand that combination is that pack converts "stuff" to an octet string and unpack converts an octet string to "stuff" according to template strings. Unpacking with a different template than was used for packing reinterprets the octet string, essentially "type-punning" the data. (Type-punning is a C trick where the element of a C union object that is read is not the element that was most recently written.)

        This explanation is how I remember when to use pack and when to use unpack.