【问题标题】:Why strtol() returns -1 for very large numbers?为什么 strtol() 对非常大的数字返回 -1?
【发布时间】:2018-06-25 16:35:24
【问题描述】:

为什么 strtol() 在 C 中对非常大的数字返回 -1?

例如:

#include <stdio.h>
#include <string.h>
int main() {
    long long i = strtoll("135898539853985649864867468746876587784760", NULL, 10);
    printf("i = %lld\n", i);
    return 0;
}

【问题讨论】:

  • 对于大多数平台来说,LLONG_MAX 是 64 位 9223372036854775807 签名的。这比您提供的要少得多。其次,strtol 无论如何都会返回一个long,你会想要使用strtoll,它仍然不适合,但至少返回正确的类型。这个main里面有三行代码,有两行坏掉了。可能需要再次点击文本。
  • 您正在打印一个long long 值,其格式为普通int。那是在误导你。它返回LONG_MAX
  • %dlong long 的错误格式说明符,导致未定义行为。将其更改为%lld
  • @gem C 规范中没有任何内容可以防止“A long is more than 63 bits”,尽管这并不常见。
  • @GemTaylor 在这种情况下的行为应该是将读取位置移动到数字序列的末尾,但返回LONG_MAX并将errno设置为ERANGE

标签: c type-conversion strtol


【解决方案1】:

为什么 strtol() 在 C 中对非常大的数字返回 -1?

由于使用了错误的打印说明符/变量组合,代码行为异常。那是未定义的行为

long long i = .... printf("i = %d\n", i); 应该在启用了良好警告的编译时发出警告。节省时间并启用所有警告。

使用匹配的打印说明符/变量:@Jonathan Leffler@Ian Abbott

long long i = ....
...
//           vvv
printf("i = %lld\n", i);

使用strtoll() 将字符串转换为long long 会更有意义

int main() {
    //  long long i = strtol("1358...
    long long i = strtoll("135898539853985649864867468746876587784760", NULL, 10);
    // printf("i = %d\n", i);
    printf("i = %lld\n", i);
    return 0;
}

打印errno 的值表示溢出。测试endptr 将指示是否发生了一些转换。

由于 strtoll() 可以将 errno 设置为非零值,因此在函数调用之前设置为 0 以便之后很好地评估函数的效果,并且代码不会继承一些早期的非零值。

    char *endptr;  
    errno = 0;
    long long i = strtoll(some_string, &endptr, 10);
    int errnum = errno;
    printf("i = %lld\n", i);
    if (some_string == endptr) {
      puts("No conversion");
    } else {
      if (errnum == ERANGE) { 
        puts("Overflow");
      } else if (errnum) {
        puts("Implementation specific error");
      } 
    }

【讨论】:

  • “使用匹配的打印说明符/变量:”信用到期:@JonathanLeffler 在我之前提到过它(尽管我更详细地介绍了)。
  • 请注意,对printf() 的调用可能会设置errno(可能不会,但Solaris 上的标准库曾经(并且可能仍然会)将errno 设置为ENOTTY当标准输出不是终端时——即使它没有报告错误)。您应该在调用strtoll() 后立即捕获errno 的值(例如int errnum = errno;),然后测试errnum 而不是errno,或者移动值的打印直到您完成测试@ 987654342@.
  • @JonathanLeffler True int errnum = errno; 如果代码在评估之前调用某个函数或多次使用errno,这是一个很好的做法。
  • 我也鼓励你在文中提到,在调用strtoll之前必须立即将errno设置为零,因为你无法查看它的返回值来判断它是否失败,所以你需要无条件地检查errno,所以你需要确保如果它不为零,那么设置它的是strtoll。 (您的代码很好,只是不清楚为什么顶部的 errno = 0 是必要的。)
【解决方案2】:

实际上,strtol() 返回了正确的值LONG_MAX。您使用了错误的格式字符串 - 尝试printf("i = %lli\n", i);%d 用于输出普通的int

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-19
    • 1970-01-01
    • 2021-11-26
    相关资源
    最近更新 更多