What is the difference between sscanf or atoi to convert a string to an integer?

gcc 4.4.4 c89

What is the best way to convert a string to an integer value.

I tried 2 different atoi and sscanf methods. Both work as expected.

char digits[3] = "34"; int device_num = 0; if(sscanf(digits, "%d", &device_num) == EOF) { fprintf(stderr, "WARNING: Incorrect value for device\n"); return FALSE; } 

or using atoi

 device_num = atoi(digits); 

I thought sscanf would be better since you can check for errors. However, atoi does not do any checks.

+56
c atoi scanf
Aug 6 2018-10-10T00:
source share
6 answers

You have 3 options:

  • atoi

This is probably the fastest if you use it in performance-critical code, but it does not report errors. If the string does not start with an integer, it will return 0. If the string contains garbage after the integer, it converts the initial part and ignores the rest. If the number is too large to match int , no behavior is specified.

  1. sscanf

Some error messages, and you have a lot of flexibility for what type to store (signed / unsigned versions of char/short/int/long/long long/size_t/ptrdiff_t/intmax_t ).

The return value is the number of successful conversions, so scanning for "%d" will return 0 if the string does not start with an integer. You can use "%d%n" to store the index of the first character after an integer that is read in another variable, and thus check whether the entire string has been converted or if there is unwanted information after that. However, like atoi , integer overflow behavior is not specified.

  1. strtol and family

Reliable error reporting if you set errno to 0 before making a call. Return values ​​are indicated when overflowing and errno will be set. You can choose any base of numbers from 2 to 36 or specify 0 as the base for automatic interpretation of leading 0x and 0 as hexadecimal and octal, respectively. The choice of type for conversion is the signed / unsigned versions of long/long long/intmax_t .

If you need a smaller type, you can always save the result in a temporary variable long or unsigned long and check the overflow yourself.

Since these functions take a pointer to a pointer argument, you also get a pointer to the first character following the converted integer, for free, so you can determine if the whole line was an integer or analyze the subsequent data in the line if necessary.




Personally, I would recommend the strtol family for most purposes. If you do something fast and dirty, atoi can satisfy your needs.

Aside, sometimes I find that I need to parse numbers, where leading spaces, signs, etc. should not be accepted. In this case, it’s quite easy to scroll your own loop, for example,

 for (x=0; (unsigned)*s-'0'<10; s++) x=10*x+(*s-'0'); 

Or you can use (for reliability):

 if (isdigit(*s)) x=strtol(s, &s, 10); else /* error */ 
+98
Aug 6 '10 at 6:45
source share

*scanf() family of functions returns the number of converted values. Therefore, you must make sure sscanf() returns 1 in your case. EOF returned for "input failure", which means that ssacnf() will never return EOF .

For sscanf() function must parse the format string and then decode the integer. atoi() has no overhead. Both problems are related to the fact that values ​​outside the range lead to undefined behavior.

You should use the strtol() or strtoul() functions, which provide much better error detection and verification. They also tell you if the entire line has been consumed.

If you want an int , you can always use strtol() and then check the return value to see if it is between INT_MIN and INT_MAX .

+9
Aug 6 '10 at 2:37
source share

To @R .. I think this is not enough to check errno for errors in strtol strtol .

 long strtol (const char *String, char **EndPointer, int Base) 

You also need to check EndPointer for errors.

+4
Mar 15 '12 at 6:27
source share

Combining R .. and PickBoy Answers for Short

 long strtol (const char *String, char **EndPointer, int Base) // examples strtol(s, NULL, 10); strtol(s, &s, 10); 
+2
Apr 10 2018-12-12T00:
source share

If there is no problem with incorrect line input or range, use the simplest ones: atoi()

Otherwise, the method with better error / range detection is neither atoi() nor sscanf() . In this good answer, everything is ready to detail error checking with atoi() and some error checking with sscanf() .

strtol() is the most stringent string to int function. But this is only the beginning. Below are detailed examples showing the correct use, so the reason for this answer was later accepted .

 // Over-simplified use int strtoi(const char *nptr) { int i = (int) strtol(nptr, (char **)NULL, 10); return i; } 

This is similar to atoi() and does not account for atoi() error detection functions.

To make full use of strtol() , you can consider various functions:

  • Conversion "--0" Detection: Examples: "xyz" or "" or "--0" ? In these cases, endptr will match nptr .

     char *endptr; int i = (int)strtol(nptr, &endptr, 10); if (nptr == endptr) return FAIL_NO_CONVERT; 
  • If the whole line is converted or only the leading part: Is "123xyz" OK?

     char *endptr; int i = (int)strtol(nptr, &endptr, 10); if (*endptr != '\0') return FAIL_EXTRA_JUNK; 
  • Determine if the value was so large, the result is not represented as long as "999999999999999999999999999999" .

     errno = 0; long L = strtol(nptr, &endptr, 10); if (errno == ERANGE) return FAIL_OVERFLOW; 
  • Determine if the value was outside the range of int , but not long . If int and long have the same range, this test is not required.

     long L = strtol(nptr, &endptr, 10); if (L < INT_MIN || L > INT_MAX) return FAIL_INT_OVERFLOW; 
  • Some implementations are outside the scope of the C standard and set errno for additional reasons, such as errno for EINVAL if no conversion was made or EINVAL The Base parameter value is not valid. . The best time to check these errno values ​​is implementation dependent.

Putting it all together: (Adjust your needs)

 #include <errno.h> #include <stdlib.h> int strtoi(const char *nptr, int *error_code) { char *endptr; errno = 0; long i = strtol(nptr, &endptr, 10); #if LONG_MIN < INT_MIN || LONG_MAX > INT_MAX if (errno == ERANGE || i > INT_MAX || i < INT_MIN) { errno = ERANGE; i = i > 0 : INT_MAX : INT_MIN; *error_code = FAIL_INT_OVERFLOW; } #else if (errno == ERANGE) { *error_code = FAIL_OVERFLOW; } #endif else if (endptr == nptr) { *error_code = FAIL_NO_CONVERT; } else if (*endptr != '\0') { *error_code = FAIL_EXTRA_JUNK; } else if (errno) { *error_code = FAIL_IMPLEMENTATION_REASON; } return (int) i; } 



Note. All the mentioned functions allow you to use leading spaces, an optional character of the main character and are subject to a change in locale. Additional code is needed for a more restrictive conversion.




Note. Continuous non-OP header change. This answer better relates to the original title "convert string to sscanf or atoi integer"

+2
Dec 14 '15 at 4:49
source share

If the user enters 34abc and you pass it to atoi, he will return 34. If you want to check the entered value, you should use isdigit for the entered string iteratively

0
Aug 6 2018-10-06T00:
source share



All Articles