473,388 Members | 932 Online

# 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
Jul 18 '05 #1
9 2243

"William S. Huizinga" <wi**************@smiths-aerospace.com> wrote in
message news:3f********@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

Jul 18 '05 #2
In article <3f********@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];
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
Jul 18 '05 #3

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
Jul 18 '05 #4
In article <3f*********************@newsreader.visi.com>, Grant Edwards wrote:
In article <3f********@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];

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!!
Jul 18 '05 #5
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

Jul 18 '05 #6
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

Jul 18 '05 #7
Skip Montanaro <sk**@pobox.com> wrote in message news:<ma**********************************@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
Jul 18 '05 #8
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];

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?

"Reads string as big endian word, (asserts len(string) in [1,2,4])"
return unpack('>%s' % {1:'b', 2:'H', 4:'l'}[len(value)], value)[0]

def writeBew(value, length):
"""
Write int as big endian formatted string,
(asserts length in [1,2,4])
"""
return pack('>%s' % {1:'b', 2:'H', 4:'l'}[length], value)

Any of those usefull?

regards Max M

Jul 18 '05 #9
"William S. Huizinga" <wi**************@smiths-aerospace.com> 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];

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?

Just for completeness, it's also possible to go back to basic style
programming.

Anton

from string import hexdigits

def hexchr(i): return hexdigits[i/16]+hexdigits[i%16]
asc = dict([(chr(i), hexchr(i)) for i in range(256)])
def tolong(s): return long(''.join(map(asc.get,s[::-1])),16)

def test():
a = '\x01\x02\x03\x04'
print tolong(a)

if __name__=='__main__':
test()
Jul 18 '05 #10

This thread has been closed and replies have been disabled. Please start a new discussion.