32

Take this example:

i = 0x12345678
print("{:08x}".format(i))
   # Shows 12345678
i = swap32(i)
print("{:08x}".format(i))
   # Should print 78563412

What would be the swap32-function()? Is there a way to byte-swap an int in Python, ideally with built-in tools?

5
  • 4
    Alternatively, the array.byteswap() method if you first convert the number into a byte-array Commented Dec 16, 2014 at 14:10
  • 3
    @aruisdante I found this question, but its title does not correspond to what is asked by the OP.... changed its title. Commented Dec 16, 2014 at 14:12
  • Your example is swapping the order of 4-bit chunks, not bytes. If you swapped the order of the four bytes, { 12 34 56 78 }, it would be { 78 56 34 12 }. Commented Feb 5, 2019 at 21:40
  • @AaronF what? Your "it would be" is exactly what I put in the comment. Commented Feb 7, 2019 at 13:02
  • My bad. I misread it has 87654321. Sorry about that. You're right. Commented Feb 7, 2019 at 18:10

5 Answers 5

36

One method is to use the struct module:

def swap32(i):
    return struct.unpack("<I", struct.pack(">I", i))[0]

First you pack your integer into a binary format using one endianness, then you unpack it using the other (it doesn't even matter which combination you use, since all you want to do is swap endianness).

Sign up to request clarification or add additional context in comments.

4 Comments

What should be the result of swap32(12345678) ?
@AerofoilKite be careful, don't be confused by the print of {:08x}, it is omitting the 0x. 12345678 != 0x12345678
@Carsten, "i" format for functions pack and unpack means signed integer. As a result, value like 0x87654321 is not handled well with your definition. To treat values as unsigned, format "I" could be used: struct.unpack("<I", struct.pack(">I", i))[0]
@ArtemZankovich Thank you! I forgot about that. I have updated my answer accordingly.
31

Big endian means the layout of a 32 bit int has the most significant byte first,

e.g. 0x12345678 has the memory layout

msb             lsb
+------------------+
| 12 | 34 | 56 | 78|
+------------------+

while on little endian, the memory layout is

lsb             msb
+------------------+
| 78 | 56 | 34 | 12|
+------------------+

So you can just convert between them with some bit masking and shifting:

def swap32(x):
    return (((x << 24) & 0xFF000000) |
            ((x <<  8) & 0x00FF0000) |
            ((x >>  8) & 0x0000FF00) |
            ((x >> 24) & 0x000000FF))

2 Comments

I will do like this, but it is not used a "built-in" functionality as I asked for. Which is why I accept the other answer.
Bitwise shift, OR, and AND are about as "built-in" as it gets.
20

From Python 3.2, you can define a function, swap32(), as the following:

def swap32(x):
    return int.from_bytes(x.to_bytes(4, byteorder='little'), byteorder='big', signed=False)

It uses an array of bytes to represent the value and reverses the order of the bytes by changing endianness during conversion back to integer.

1 Comment

Nice! Also can be easily modified for 64-bit integers.
3

The array module provides a byteswap() method for fixed sized items. The array module appears to be in versions back to Python 2.7

array.byteswap() “Byteswap” all items of the array. This is only supported for values which are 1, 2, 4, or 8 bytes in size;

Along with the fromfile() and tofile() methods, this module is quite easy to use:

import array

# Open a data file.
input_file = open( 'my_data_file.bin' , 'rb' )

# Create an empty array of unsigned 4-byte integers.
all_data = array.array( 'L' )

# Read all the data from the file.
all_data.fromfile( input_file , 16000 )               # assumes the size of the file

# Swap the bytes in all the data items.
all_data.byteswap( )

# Write all the data to a new file.
output_file = open( filename[:-4] + '.new' , 'wb' )    # assumes a three letter extension
all_data.tofile( output_file )

# Close the files.
input_file.close( )
output_file_close( )

The above code worked for me since I have fixed-size data files. There are more Pythonic ways to handle variable length files.

Comments

3

It may be simpler to use the socket library:

from socket import htonl

swapped = htonl(i)
print(hex(swapped))

That's it. This library also works in the other direction with ntohl.

1 Comment

Err, this won't work on big-endian systems. That's the whole point of htonl.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.