Need elegant way to cast four bytes into a long

Discussion in 'Python' started by William S. Huizinga, Aug 8, 2003.

  1. 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
     
    William S. Huizinga, Aug 8, 2003
    #1
    1. Advertising

  2. William S. Huizinga

    Terry Reedy Guest

    "William S. Huizinga" <> wrote in
    message news:3f33c209$...
    > 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
     
    Terry Reedy, Aug 8, 2003
    #2
    1. Advertising

  3. In article <3f33c209$>, 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?


    How about 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
     
    Grant Edwards, Aug 8, 2003
    #3
  4. 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
     
    Skip Montanaro, Aug 8, 2003
    #4
  5. In article <3f33c785$0$172$>, Grant Edwards wrote:
    > In article <3f33c209$>, 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!!
     
    Grant Edwards, Aug 8, 2003
    #5
  6. 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];


    What about:

    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
     
    Alex Martelli, Aug 8, 2003
    #6
  7. On Fri, 8 Aug 2003 10:54:38 -0500, Skip Montanaro <> 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
     
    Bengt Richter, Aug 8, 2003
    #7
  8. William S. Huizinga

    John Machin Guest

    Skip Montanaro <> wrote in message news:<>...
    > 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
     
    John Machin, Aug 8, 2003
    #8

  9. >> 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
     
    Skip Montanaro, Aug 9, 2003
    #9
  10. William S. Huizinga

    Dan Bishop Guest

    Skip Montanaro <> wrote in message news:<>...
    > >> 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
     
    Dan Bishop, Aug 9, 2003
    #10
  11. William S. Huizinga

    Max M Guest

    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?



    def readBew(value):
    "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
     
    Max M, Aug 10, 2003
    #11
  12. "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?


    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()
     
    Anton Vredegoor, Aug 11, 2003
    #12
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. jeff

    cast unsigned long to long

    jeff, Dec 27, 2005, in forum: C Programming
    Replies:
    10
    Views:
    580
    Jack Klein
    Dec 27, 2005
  2. lovecreatesbeauty
    Replies:
    6
    Views:
    348
    lovecreatesbeauty
    Jan 16, 2006
  3. Yandos
    Replies:
    12
    Views:
    5,147
    Pete Becker
    Sep 15, 2005
  4. Replies:
    5
    Views:
    303
    dprody
    Nov 5, 2007
  5. Hahnemann

    Four or Two Bytes?

    Hahnemann, May 30, 2008, in forum: C Programming
    Replies:
    22
    Views:
    661
    Barry Schwarz
    Jun 2, 2008
Loading...

Share This Page