Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   Python (http://www.velocityreviews.com/forums/f43-python.html)
-   -   Need elegant way to cast four bytes into a long (http://www.velocityreviews.com/forums/t320758-need-elegant-way-to-cast-four-bytes-into-a-long.html)

 William S. Huizinga 08-08-2003 03:30 PM

Need elegant way to cast four bytes into a long

I've got an array.array of unsigned char and would like to make a slice
of that array (e.g. a[0:4]) become one long like I would in "C" :

l = ((unsigned long *) (&a[0]))[0];

I have been getting what I want in this sort of manner :

l = 0L
l = a[0]
l += a[1] << 8
l += a[2] << 16
l += a[3] << 24

but I think that's too wordy. Is there a more intrinsic and elegant way
to do this?

---
wsh

 Terry Reedy 08-08-2003 03:49 PM

Re: Need elegant way to cast four bytes into a long

"William S. Huizinga" <wiiliam.huizinga@smiths-aerospace.com> wrote in
message news:3f33c209\$1@news.si.com...
> I've got an array.array of unsigned char and would like to make a

slice
> of that array (e.g. a[0:4]) become one long like I would in "C" :
>
> l = ((unsigned long *) (&a[0]))[0];
>
> I have been getting what I want in this sort of manner :
>
> l = 0L
> l = a[0]
> l += a[1] << 8
> l += a[2] << 16
> l += a[3] << 24
>
> but I think that's too wordy. Is there a more intrinsic and elegant

way
> to do this?

el = 0L+ a[0] + (a[1]<< 8) + (a[2]<<16) + (a[3] << 24)

is more compact and must be slightly faster (but parens are needed)

TJR

 Grant Edwards 08-08-2003 03:53 PM

Re: Need elegant way to cast four bytes into a long

In article <3f33c209\$1@news.si.com>, William S. Huizinga wrote:
> I've got an array.array of unsigned char and would like to make a slice
> of that array (e.g. a[0:4]) become one long like I would in "C" :
>
> l = ((unsigned long *) (&a[0]))[0];

Bad C programming. Your program isn't portable.

> I have been getting what I want in this sort of manner :
>
> l = 0L
> l = a[0]
> l += a[1] << 8
> l += a[2] << 16
> l += a[3] << 24
>
> but I think that's too wordy. Is there a more intrinsic and elegant way
> to do this?

l = a[0] + (a[1]<<8) + (a[2]<<16) + (a[3]<<24)

Or you can use struct:

l = struct.unpack("<I","".join([chr(b)for b in a]))[0]

I think that the former is more obvious.

--
Grant Edwards grante Yow! I always liked FLAG
at DAY!!
visi.com

 Skip Montanaro 08-08-2003 03:54 PM

Re: Need elegant way to cast four bytes into a long

wsh> I have been getting what I want in this sort of manner :

wsh> l = 0L
wsh> l = a[0]
wsh> l += a[1] << 8
wsh> l += a[2] << 16
wsh> l += a[3] << 24

wsh> but I think that's too wordy. Is there a more intrinsic and
wsh> elegant way to do this?

You mean like this:

l = long(a[0] + a[1] << 8 + a[2] << 16 + a[3] << 24)

You can use struct.unpack as well, though I'd be hard-pressed to get the
details correct. You'd be better off with "pydoc struct".

Skip

 Grant Edwards 08-08-2003 04:01 PM

Re: Need elegant way to cast four bytes into a long

In article <3f33c785\$0\$172\$a1866201@newsreader.visi.com>, Grant Edwards wrote:
> In article <3f33c209\$1@news.si.com>, William S. Huizinga wrote:
>> I've got an array.array of unsigned char and would like to make a slice
>> of that array (e.g. a[0:4]) become one long like I would in "C" :
>>
>> l = ((unsigned long *) (&a[0]))[0];

>
> Bad C programming. Your program isn't portable.

Aside from the endian issue, it may even cause a bus fault or
completely bogus value on many architectures (ARM, SPARC,
etc.). It's actually quite difficult to duplicate that sort of
behavior in Python. ;)

--
Grant Edwards grante Yow! Remember, in 2039,
at MOUSSE & PASTA will
visi.com be available ONLY by
prescription!!

 Alex Martelli 08-08-2003 04:30 PM

Re: Need elegant way to cast four bytes into a long

William S. Huizinga wrote:

> I've got an array.array of unsigned char and would like to make a slice
> of that array (e.g. a[0:4]) become one long like I would in "C" :
>
> l = ((unsigned long *) (&a[0]))[0];

b = array.array('L')
b.fromstring(a[0:4].tostring())
l = b[0]

I think this should faithfully reproduce the endianness-related
unportability of that C fragment (cannot necessarily reproduce
crashes due to possible use of misaligned pointers, though:-).

Actually, I believe you do not really need the .tostring call
in modern Python -- just b.fromstring(a[0:4]) should be
equivalent (and faster). Better, if you need to transform
into longs _many_ adjacent segments of 4 bytes each, this
approach does generalize, and speed is good. Finally, you
can remedy endianness issue with the .byteswap method...

Alex

 Bengt Richter 08-08-2003 07:23 PM

Re: Need elegant way to cast four bytes into a long

On Fri, 8 Aug 2003 10:54:38 -0500, Skip Montanaro <skip@pobox.com> wrote:

>
> wsh> I have been getting what I want in this sort of manner :
>
> wsh> l = 0L
> wsh> l = a[0]
> wsh> l += a[1] << 8
> wsh> l += a[2] << 16
> wsh> l += a[3] << 24
>
> wsh> but I think that's too wordy. Is there a more intrinsic and
> wsh> elegant way to do this?
>
>You mean like this:
>
> l = long(a[0] + a[1] << 8 + a[2] << 16 + a[3] << 24)
>
>You can use struct.unpack as well, though I'd be hard-pressed to get the
>details correct. You'd be better off with "pydoc struct".
>
>Skip
>

This won't be fast, but you get to play with 2.3 ;-)

>>> a = '\x01\x02\x03\x04'
>>> sum([ord(c)<<8*i for i,c in enumerate(a)])

67305985
>>> hex(sum([ord(c)<<8*i for i,c in enumerate(a)]))

'0x4030201'

or big-endian:

>>> a = '\x01\x02\x03\x04'
>>> sum([ord(c)<<8*i for i,c in enumerate( a[::-1])])

16909060
>>> hex(sum([ord(c)<<8*i for i,c in enumerate( a[::-1])]))

'0x1020304'

Regards,
Bengt Richter

 John Machin 08-08-2003 10:07 PM

Re: Need elegant way to cast four bytes into a long

Skip Montanaro <skip@pobox.com> wrote in message news:<mailman.1060358114.21520.python-list@python.org>...
> wsh> I have been getting what I want in this sort of manner :
>
> wsh> l = 0L

The above line is redundant.

> wsh> l = a[0]
> wsh> l += a[1] << 8
> wsh> l += a[2] << 16
> wsh> l += a[3] << 24
>
> wsh> but I think that's too wordy. Is there a more intrinsic and
> wsh> elegant way to do this?
>
> You mean like this:
>
> l = long(a[0] + a[1] << 8 + a[2] << 16 + a[3] << 24)
>

Bzzzzzt. Oh the joys of operator precedence!

Python 2.2.3 (#42, May 30 2003, 18:12:08) [MSC 32 bit (Intel)] on win32
>>> a = range(0x11,0x55,0x11)
>>> hex(a[0] + a[1] << 8 + a[2] << 16 + a[3] << 24)

'0x0'
>>> hex(a[0] + (a[1] << 8) + (a[2] << 16) + (a[3] << 24))

'0x44332211'
>>> hex(a[0] | a[1] << 8 | a[2] << 16 | a[3] << 24)

'0x44332211'

See http://www.python.org/doc/current/ref/summary.html

 Skip Montanaro 08-09-2003 05:06 PM

Re: Need elegant way to cast four bytes into a long

>> You mean like this:
>>
>> l = long(a[0] + a[1] << 8 + a[2] << 16 + a[3] << 24)
>>

John> Bzzzzzt. Oh the joys of operator precedence!

Yeah, I realized that after seeing a couple other responses. Should have
kept my mouth shut. I tend to think of << and >> as X2 and /2 operators and
thus mentally lump them together with * / and %. Fortunately, I don't do
much bit twiddling or I'd be in real trouble...

Skip

 Dan Bishop 08-09-2003 10:49 PM

Re: Need elegant way to cast four bytes into a long

Skip Montanaro <skip@pobox.com> wrote in message news:<mailman.1060448895.18308.python-list@python.org>...
> >> You mean like this:
> >>
> >> l = long(a[0] + a[1] << 8 + a[2] << 16 + a[3] << 24)
> >>

> John> Bzzzzzt. Oh the joys of operator precedence!
>
> Yeah, I realized that after seeing a couple other responses. Should have
> kept my mouth shut. I tend to think of << and >> as X2 and /2 operators and
> thus mentally lump them together with * / and %. Fortunately, I don't do
> much bit twiddling or I'd be in real trouble...

One correct way of writing the expression without parentheses is

a[0] | a[1] << 8 | a[2] << 16 | a[3] << 24

All times are GMT. The time now is 01:44 PM.