将字符串转换为整数的sscanf或atoi有什么区别?

时间:2010-08-06 02:29:16

标签: c scanf atoi

gcc 4.4.4 c89

将字符串转换为整数值更好。

我尝试了两种不同的方法atoi和sscanf。两者都按预期工作。

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;
}

或使用atoi

device_num = atoi(digits);

我认为sscanf会更好,因为你可以检查错误。但是,atoi没有做任何检查。

6 个答案:

答案 0 :(得分:104)

您有3个选择:

  1. atoi
  2. 如果您在性能关键代码中使用它,这可能是最快的,但它没有错误报告。如果字符串不是以整数开头,则返回0.如果字符串在整数后面包含垃圾,它将转换初始部分并忽略其余部分。如果数字太大而不适合int,则行为未指定。

    1. sscanf
    2. 某些错误报告,您可以灵活地存储要存储的类型(char/short/int/long/long long/size_t/ptrdiff_t/intmax_t的签名/未签名版本)。

      返回值是成功的转换次数,因此如果字符串不以整数开头,则对"%d"的扫描将返回0。您可以使用"%d%n"来存储在另一个变量中读取的整数之后的第一个字符的索引,从而检查整个字符串是否已转换或之后是否有垃圾。但是,与atoi类似,未指定整数溢出的行为。

      1. strtol和家人
      2. 强大的错误报告,前提是您在拨打电话前将errno设置为0。返回值在溢出时指定,errno将被设置。您可以选择2到36之间的任意数字,或指定0作为基数,分别将前导0x0自动解释为十六进制和八进制。要转换为的类型的选择是long/long long/intmax_t的签名/无符号版本。

        如果您需要较小的类型,您始终可以将结果存储在临时longunsigned long变量中,并自行检查溢出。

        由于这些函数采用指向指针参数的指针,因此您还可以获得指向转换后的整数后面的第一个字符的指针,这样您就可以判断整个字符串是整数还是解析字符串中的后续数据(如果需要)


        就个人而言,我会建议strtol家庭用于目的。如果你正在做一些快速和肮脏的事情,atoi可能会满足你的需求。

        顺便说一句,有时我发现我需要解析前导空格,符号等不被接受的数字。在这种情况下,很容易推出自己的循环,例如,

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

        或者你可以使用(为了健壮性):

        if (isdigit(*s))
            x=strtol(s, &s, 10);
        else /* error */ 
        

答案 1 :(得分:10)

*scanf()函数族返回转换的值的数量。所以你应该检查以确保sscanf()在你的情况下返回1。 “输入失败”会返回EOF,这意味着ssacnf()永远不会返回EOF

对于sscanf(),函数必须解析格式字符串,然后解码整数。 atoi()没有那个开销。两者都存在超出范围的值导致未定义行为的问题。

您应该使用strtol()strtoul()函数,它们可以提供更好的错误检测和检查功能。他们还会告诉您整个字符串是否被消耗。

如果您想要int,可以随时使用strtol(),然后检查返回的值,看它是否位于INT_MININT_MAX之间。

答案 2 :(得分:4)

致@R ..我认为在errno调用中检查strtol错误检测是不够的。

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

您还需要检查EndPointer是否有错误。

答案 3 :(得分:2)

为了简洁而结合R ..和PickBoy答案

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

// examples
strtol(s, NULL, 10);
strtol(s, &s, 10);

答案 4 :(得分:2)

如果不关心无效的字符串输入或范围问题,请使用最简单的:atoi()

否则,具有最佳错误/范围检测的方法既不是atoi()也不是sscanf()This good answer所有准备好的详细信息都表明缺少使用atoi()进行错误检查以及使用sscanf()进行某些错误检查。

strtol()是将字符串转换为int时最严格的功能。然而,这只是一个开始。下面是详细的示例,以显示正确的用法,以及accepted one之后的答案的原因。

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

这就像atoi()一样,忽略了使用strtol()的错误检测功能。

要完全使用strtol(),需要考虑各种功能:

  1. 检测无转化:示例:"xyz",或"""--0"?在这些情况下,endptr将与nptr匹配。

    char *endptr;
    int i = (int)strtol(nptr, &endptr, 10);
    if (nptr == endptr) return FAIL_NO_CONVERT;
    
  2. 整个字符串应该转换还是仅转换为引导部分:"123xyz"是否正常?

    char *endptr;
    int i = (int)strtol(nptr, &endptr, 10);
    if (*endptr != '\0') return FAIL_EXTRA_JUNK;
    
  3. 检测值是否过大,结果无法表示为long "999999999999999999999999999999"

    errno = 0;
    long L = strtol(nptr, &endptr, 10);
    if (errno == ERANGE) return FAIL_OVERFLOW;
    
  4. 检测该值是否超出int范围,但不是long。如果intlong具有相同的范围,则不需要此测试。

    long L = strtol(nptr, &endptr, 10);
    if (L < INT_MIN || L > INT_MAX) return FAIL_INT_OVERFLOW;
    
  5. 某些实施超出了C标准,并设置了errno,原因还有其他原因,例如errno to EINVAL in case no conversion was performedEINVAL The value of the Base parameter is not valid.。测试这些errno值的最佳时间取决于实现。

  6. 将所有这些放在一起:(根据您的需要调整)

    #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;
    }
    

    注意:所有提到的功能都允许前导空格,可选的前导符号字符,并受 locale 更改的影响。更严格的转换需要额外的代码。

    注意:非OP标题更改偏重。这个答案更适用于原始标题“将字符串转换为整数sscanf或atoi”

答案 5 :(得分:0)

如果用户输入34abc并将它们传递给atoi,它将返回34。 如果要验证输入的值,则必须迭代地在输入的字符串上使用isdigit