0

I'm trying to imitate the behavior of some parts of a C program in Python. They are both reading a binary file where each record is length->data. The C program will pull the length byte from the file, and regardless of whether it's positive or negative, ntohl() will return the correct length. However, in Python, even though the length record is the same value, when it's negative I'm getting an OverflowError:

length: 419495936

ntohl: 281

length: -2147418112

OverflowError: can't convert negative number to unsigned long

as compared to C:

length: 419495936

ntohl: 281

length: -2147418112

ntohl: 384

What am I doing wrong here? How do I get Python to produce the same results as C?

Edit with code

Here's the C code:

while (fread(&rec_len, sizeof(unsigned int),  1, fp1) != 0) {
    printf("length: %d\n", rec_len);
    rec_len = ntohl(rec_len);
    printf("ntohl: %d\n", rec_len);

And here's Python:

with open(file, "rb") as f:
    pSize = struct.unpack('<i', f.read(4))[0]
    print "length: " + str(pSize)
    packetSize = socket.ntohl(pSize)
    print "ntohl: " + str(packetSize)
    while packetSize > 0:
        packet = f.read(packetSize)
        pSize = struct.unpack('<i', f.read(4))[0]
        print "length: " + str(pSize)
        packetSize = socket.ntohl(pSize)
        print "ntohl: " + str(packetSize)
Dave
  • 1,420
  • 3
  • 17
  • 25
  • 1
    This only works in C because it doesn't protect you from overflowing. Python integers don't overflow, and it doesn't make sense to consider a very negative number to be the same as some large positive number. – Wooble Jul 18 '12 at 13:07
  • What is your Python version? Python might show inconsistent behavior on different versions in this case http://stackoverflow.com/questions/5995971/python-error-with-socket-ntohl – jfs Jul 18 '12 at 13:19

1 Answers1

6

You need to pass a positive number to htonl(). If you can't change how you read the value, you can use the following code:

>>> socket.htonl((-2147418112) & 0xffffffff)
384L

EDIT: having looked at your code, you could change struct.unpack to use '<I' which gives you an unsigned number, or even to use '>I' or '!I' which negates the need for ntohl() afterwards.

Rodrigo Queiro
  • 1,324
  • 8
  • 15