What is the difference between strtol and strtoul?
Asked Answered
S

3

7

I met some unexcepted result of strtol in c

Here is the sample program.

#include <string.h>
#include <stdio.h>    
#include <stdlib.h>

int main()
{
    printf("%x\n", strtol("0xfffff70A", NULL, 0));
    return 0;
}

and the output of this simple program is

0x7fffffff

rather than 0xfffff70A. And if I use strtoul, the result is exactly 0xfffff70a. I am using a 32-bit machine, and I wonder what happens. PS. I am using gcc 4.7.2

Stoller answered 23/5, 2013 at 10:24 Comment(2)
Set errno to 0 before calling strtol or strtoul and check it afterwards. Do not use the value if errno has a different value.Maryrosemarys
Nice question, by the way: Next to minimal code example, input, observed output, expected output. +1 for making this so easy to answer.Adda
H
7

From 7.22.1.4 paragraph 8 (of the N1570 draft of the 2011 edition of the standard):

If the correct value is outside the range of representable values, LONG_MIN, LONG_MAX, LLONG_MIN, LLONG_MAX, ULONG_MAX, or ULLONG_MAX is returned (according to the return type and sign of the value, if any), and the value of the macro ERANGE is stored in errno.

Since the correct value of your input string is too large for the type, you get LONG_MAX, and errno is set to ERANGE.

Whenever one of the strto(u)l(l) functions returns one of the TYPE_MAX or TYPE_MIN values, you need to check errno to find out whether it's a correct result, or your input was out-of-range.

Hartung answered 23/5, 2013 at 10:52 Comment(10)
Damn, I was just about to paste the same. :-D @PascalCuoq: Behaviour of the strto... functions is very well-defined even in case of overflows. That's what makes them superior to e.g. *scanf() functions for parsing numerical input.Adda
Can you also specify from where you're quoting?Oralle
@OlafDietsche: That would be ISO/IEC 9899 (the C language standard).Adda
@Adda Not everybody knows that :-)Oralle
In contrast, why can (int)strtoul("-2",NULL,0) return the "correct" value?Stoller
@Stoller From paragraph 5: "If the subject sequence begins with a minus sign, the value resulting from the conversion is negated (in the return type)." The "2" part of the input is parsed as the value 2 of type unsigned long. Then that value is negated, that makes it ULONG_MAX + 1 - 2, (the mathematical result is reduce modulo ULONG_MAX + 1 to obtain a value in the range [0, ULONG_MAX]). Then that is converted to int in an implementation-defined manner (assuming ULONG_MAX > INT_MAX). Usually, the least significant bits are just reinterpreted, and in two's complement that's -2Hartung
@Adda You are referring to a mistake that was in my answer for only two minutes! I remembered and fixed it immediately. You are right, functions of this family have well-defined behavior as long as they are passed a well-formed string.Wearable
@PascalCuoq: I was only here for a minute or so. ;-) Actually the strto*() functions are well-defined even for non-well-formed string. Nevermind, I think this was answered to satisfaction. ;-)Adda
@Adda Here is a use of strtol() that results in undefined behavior. The undefined behavior is caused by s not being a well-formed string. ideone.com/Qs2i7nWearable
@PascalCuoq: Ah... OK, that kind of non-well-formed-ness. ;-) I bow out of the discussion, you found a way to break the function. ;-)Adda
P
1

You're running into overflow of the long type, which is signed.

You probably should use:

print("%lx\n", strtoul("0xfffff70a", NULL, 0));
                    ^
                    |
                 important!

instead, note the 'u' for "unsigned" (see manual page).

Also note that you can't print an unsigned long with plain %x, you need to qualify it as being bigger than int.

Philosopher answered 23/5, 2013 at 10:53 Comment(0)
W
0

Your architecture has a 32-bit long type. 0xfffff70A is not representable as a signed 32-bit long. errno should have been set to ERANGE.

In 2's complement, representable values for 32-bit signed integers range from -0x80000000 to 0x7fffffff.

Wearable answered 23/5, 2013 at 10:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.