【问题标题】:string to long, not giving me the correct answer字符串变长,没有给我正确的答案
【发布时间】:2017-07-31 08:46:30
【问题描述】:

我正在尝试将存储在 c 字符串中的数字转换为 long int。但我没有得到预期的输出:

char str[] = "987654321012345";
long int num ;
num = 0;
//num = atol(str);
num = strtol(str, (char **) NULL, 10);
printf("%ld", num);

输出:821493369

gcc 版本 4.4.7 20120313 (Red Hat 4.4.7-16) 你能告诉我我在这里做错了什么吗?谢谢。

【问题讨论】:

  • 您确定long 足够大吗?你是 64 位系统吗?也许您应该使用long longstrtoll"%lld"
  • 是的,我使用的是 64 位拱门。我已经尝试过使用 strtoll 并且结果是一样的。
  • 有什么问题?在我看来finelong long
  • 我使用 gcc 版本 4.4.7 20120313 (Red Hat 4.4.7-16) 得到输出 821493369 而不是 987654321012345
  • sizeof(long)sizeof(long long) 报告什么?一个或两个都说8?那么你应该没有问题。你还记得把你的数据类型改成long long吗?并将printf格式改为"%lld"?

标签: c linux string long-integer


【解决方案1】:

除了使用long long,您还可以使用stdint.h 中的精确宽度 类型。例如,要保证 64 位 有符号 数字,您可以使用 int64_t 类型。无论您做什么,不要将 NULL 转换为char **始终 验证您的转化。例如,

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

int main (void) {

    char str[] = "987654321012345";
    long num = 0;
    errno = 0;

    num = strtol (str, NULL, 10);
    if (errno) {    /* validate strtol conversion */
        perror ("strtol conversion failed.");
        return 1;
    }

    printf ("%ld\n", num);

    return 0;
}

使用/输出示例

$ ./bin/strtoltst
987654321012345

您可以对转换进行额外的错误检查,但至少要确保在调用 strtolstrtoll 后未设置 errno

如果您想使用保证宽度类型,那么您可以进行以下更改:

...
#include <stdint.h>
...
    int64_t num = 0;
    ...
    num = strtoll (str, NULL, 10);

结果是一样的。

【讨论】:

  • 很高兴它有帮助。 C 有很多东西要学。慢慢来,享受这个过程:)
  • 谢谢大卫 C. Rankin :)
  • 由于完整声明中的第二个指针是NULL (**endptr),您所能做的就是检查errno 和ERANGE 值。如果有第二个指针,那么我们可以检查 'no-digits' 和 0,但没有它,你只有 errno
  • 这里的要点是检查转换是否成功,如果未设置errno,则不会发生错误。是的,检查LLONG_MAXLLONG_MIN 的任何退货是适当的,但完全没有必要,除非对其中一项采取替代行动。在这里,我们正在为一个失败的转换保释——就是这样。我不反对这些检查,但我不同意任何关于 errno 检查错误的建议。
  • @PatrickTrentin - 是的,即使是盲松鼠也会时不时地找到一个坚果,但很高兴知道,如果我跑线了,你们两个都会很快教我:)
【解决方案2】:

我可以复制和修复。

重现问题的代码

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

int main()
{
    char str[] = "987654321012345";
    long int num ;
    char *ix;
    num = 0;
    //num = atol(str);
    num = strtol(str, &ix, 10);
    printf("%ld\n", num);
    printf("%lu\n", sizeof(long));
    return 0;
}

按预期提供:

821493369
8

编译警告后

警告:strtoll 的隐式声明

原因:由于 strtoll 未声明,因此假定返回 int,因此 long 值首先被截断为 int,然后再提升为 long。

修复:只需取消注释 #include &lt;stdlib.h&gt; 行...

结论:警告不应被忽视!

【讨论】:

  • 感谢 @Serge Ballesta 重现问题并给出输出按原样出现的原因,已投票赞成。
  • @CppLearner:这就是为什么问题应该包含minimal reproducible example :-)
  • ,我的错,我为此道歉。我以为我提供了全部信息。非常感谢您抽出时间对此进行调查。真诚的。
  • 这个答案很好地解决了 OP 的结果。
【解决方案3】:

您应该使用long long 作为您号码的数据类型。

char str[] = "987654321012345";
long long num = strtoll(str, (char **)NULL, 10);
printf("%lld", num);

【讨论】:

  • 已经尝试过了,我使用 strtoll 得到了相同的输出。
  • @CppLearner 在使用printf 打印时,您是否使用了strtolllld 格式标志?
【解决方案4】:

根据C data type

  • 长符号整数类型。至少能够包含 [−2,147,483,647, +2,147,483,647] 范围;因此,它的大小至少为 32 位。
  • 长无符号整数类型。至少能够包含 [0, 4,294,967,295] 范围;

还不够,所以您需要long longunsigned long long 并使用%lli%llu

【讨论】:

  • 即使这样也不行 :( char str[] = "987654321012345"; unsigned long long int num ; num = 0; //num = atol(str); num = strtoll(str, ( char **) NULL, 10); printf("%llu", num);
  • 如果 OP 代码使用 32 位 long,那么输出将是 2147483648,而不是 821493369。问题不是由于 long 大小造成的。
  • @chux,对我来说,不是取最大值而是二进制值适合类型大小,例如:在我的计算机上 sizeof(long) = 8, 987654321012345 -> 11100000100100010000110000111101101111111001111001 sizeof(int) = 4, 111000001001000100 [00110000111101101111111001111001] -> 821493369
  • 1 通过使用最大值而不是大小,代码会考虑填充,这是某些实现中很少见的方面。 2 这个答案确实解决了转换问题,但在 OP 的机器上,long 的大小为 8 个字节,strtol(987654321012345, ...) 不是 OP 的范围问题。
【解决方案5】:

“987654321012345”太大了。

  • Strol 正在输出长类型变量。
  • 长值是 –2,147,483,648 到 2,147,483,647。

试试

char str[] = "987654321012345";
char *pEnd;
long long num;
num = 0;
num = strtoull(str,&pEnd, 10);
printf("%lld", num);
return 0;
  • long long 而不是 long
  • strtoull 代替 strtol

  • %lld 而不是 %ld

【讨论】:

  • "987654321012345" 对于 OP 的 64 位 long不会太大。 “多头值为 –2,147,483,648 至 2,147,483,647。”是 C 中的最小范围。long 可能更宽,就像 OP 的情况一样。 OP 的代码和这都缺少strto*() 原型,因此存在相同的问题。不清楚为什么这个答案建议strtoull() 而不是strtoll()
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-23
  • 2021-10-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多