X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=pod%2Fperlpacktut.pod;h=1cb127e0b9073582e9b299b5ee3f39b874e92181;hb=3246d7a3ad86dfa806dd7e514ae5fd2dacd5c0ef;hp=80c784b455c825884a3f427d2846f6d754018a38;hpb=497043642ba2050cd87b28b50f6a01a0f50d0e90;p=p5sagit%2Fp5-mst-13.2.git diff --git a/pod/perlpacktut.pod b/pod/perlpacktut.pod index 80c784b..1cb127e 100644 --- a/pod/perlpacktut.pod +++ b/pod/perlpacktut.pod @@ -400,7 +400,7 @@ containing a stack frame as it happens on an Intel 8086: First, we note that this time-honored 16-bit CPU uses little-endian order, and that's why the low order byte is stored at the lower address. To -unpack such a (signed) short we'll have to use code C. A repeat +unpack such a (unsigned) short we'll have to use code C. A repeat count unpacks all 12 shorts: my( $ip, $cs, $flags, $ax, $bx, $cd, $dx, $si, $di, $bp, $ds, $es ) = @@ -459,16 +459,47 @@ to the data length. (But make sure to read L<"Lengths and Widths"> before you really code this!) +=head2 Byte-order modifiers + +In the previous sections we've learned how to use C, C, C and +C to pack and unpack integers with big- or little-endian byte-order. +While this is nice, it's still rather limited because it leaves out all +kinds of signed integers as well as 64-bit integers. For example, if you +wanted to unpack a sequence of signed big-endian 16-bit integers in a +platform-independent way, you would have to write: + + my @data = unpack 's*', pack 'S*', unpack 'n*', $buf; + +This is ugly. As of Perl 5.9.2, there's a much nicer way to express your +desire for a certain byte-order: the C> and C> modifiers. +C> is the big-endian modifier, while C> is the little-endian +modifier. Using them, we could rewrite the above code as: + + my @data = unpack 's>*', $buf; + +As you can see, the "big end" of the arrow touches the C, which is a +nice way to remember that C> is the big-endian modifier. The same +obviously works for C>, where the "little end" touches the code. + +You will probably find these modifiers even more useful if you have +to deal with big- or little-endian C structures. Be sure to read +L<"Packing and Unpacking C Structures"> for more on that. + =head2 Floating point Numbers For packing floating point numbers you have the choice between the -pack codes C and C which pack into (or unpack from) single-precision or -double-precision representation as it is provided by your system. (There +pack codes C, C, C and C. C and C pack into (or unpack +from) single-precision or double-precision representation as it is provided +by your system. If your systems supports it, C can be used to pack and +unpack extended-precision floating point values (C), which +can offer even more resolution than C or C. C packs an C, +which is the floating point type used by Perl internally. (There is no such thing as a network representation for reals, so if you want to send your real numbers across computer boundaries, you'd better stick to ASCII representation, unless you're absolutely sure what's on the other -end of the line.) +end of the line. For the even more adventuresome, you can use the byte-order +modifiers from the previous section also on floating point codes.) @@ -664,7 +695,7 @@ simply (Note that the template C would only have packed C<$str[0]> in full length.) - + To pack dates stored as triplets ( day, month, year ) in an array C<@dates> into a sequence of byte, byte, short integer we can write @@ -818,6 +849,12 @@ section right away with the terse remark that C structures don't contain anything else, and therefore you already know all there is to it. Sorry, no: read on, please. +If you have to deal with a lot of C structures, and don't want to +hack all your template strings manually, you'll probably want to have +a look at the CPAN module C. Not only can it parse +your C source directly, but it also has built-in support for all the +odds and ends described further on in this section. + =head2 The Alignment Pit In the consideration of speed against memory requirements the balance @@ -941,6 +978,32 @@ the very best we can do: my $gappy = pack( 'c x![s] s c x![l!] l!', $c1, $s, $c2, $l ); +=head2 Dealing with Endian-ness + +Now, imagine that we want to pack the data for a machine with a +different byte-order. First, we'll have to figure out how big the data +types on the target machine really are. Let's assume that the longs are +32 bits wide and the shorts are 16 bits wide. You can then rewrite the +template as: + + my $gappy = pack( 'c x![s] s c x![l] l', $c1, $s, $c2, $l ); + +If the target machine is little-endian, we could write: + + my $gappy = pack( 'c x![s] s< c x![l] l<', $c1, $s, $c2, $l ); + +This forces the short and the long members to be little-endian, and is +just fine if you don't have too many struct members. But we could also +use the byte-order modifier on a group and write the following: + + my $gappy = pack( '( c x![s] s c x![l] l )<', $c1, $s, $c2, $l ); + +This is not as short as before, but it makes it more obvious that we +intend to have little-endian byte-order for a whole group, not only +for individual template codes. It can also be more readable and easier +to maintain. + + =head2 Alignment, Take 2 I'm afraid that we're not quite through with the alignment catch yet. The