Unpacking Wrong-Endian Signed Shorts/Longs
[email protected] ("Brian de Ford") Sat, 09 Dec 2006 15:43:26 +0000
| Newsgroups | perl.perlfaq.workers |
|---|---|
| Message-ID | <[email protected]> |
Hi
Once upon a time I had to unpack signed longs in big-endian (network)
format on a little-endian machine. Because I was in a hurry, and
because I just needed to be sure I understood the file format correctly
at that point, and because I couldn't find a better way of doing it in the
FAQs or with google, I used a horrible kluge.
Many moons later that proof-of-concept had to be turned into something
usable. Being a bear of very little brain, I had to think a long time
before the blindingly obvious hit me. And because it's not in the FAQ
(perhaps because nobody else ever needed to do it) I thought you might
be interested.
It's an approach that works with little-endian, big-endian or scrambled-
endian (a neologism I just coined for what perlfunc calls "weirder byte
orders") machines without requiring a test for the architecture. You can
test for the machine's architecture if you want, and that way you can get
a speed-up if you expect the usual case is right-endian data (or a
slow-down if you expect the usual case is wrong-endian data). I suspect
that machines with weird sign representations (like ones complement or
sign+magnitude) may give erroneous results, but you can't have everything.
Assuming the data consists of signed longs in network byte order:
@data = unpack('l*', pack('L*', unpack('N*', $data_string)));
works whether the data is right-endian or wrong-endian. If the common
case is that the machine has the same endianness as the data then an
architecture test is desirable, using a single unpack for same-endian
data.
Like I said, blindingly obvious. But it took me too long to figure it
out, so maybe it's worthy of the FAQ. OTOH, if worthiness for the FAQ
is based upon me taking a long time to figure it out, you'd also need to
add that it's a good idea for males to unzip their flies and extract their
penises before urinating... :)