【问题标题】:std::stoi() takes first number in string?std::stoi() 取字符串中的第一个数字?
【发布时间】:2016-07-31 23:34:41
【问题描述】:

当我注意到它从字符串值“25”返回整数值 25 时,我在程序中使用 std::stoi() 将字符串值转换为整数值。

这让我很困惑,因为当字符串以非数字开头时,invalid_argument 会引发异常。例如,“,25”会抛出一个 invalid_exception。基于此,我假设如果整个字符串值不是数字,则会引发异常。这不是我意识到的情况。例如,“25,543”将返回 25。

我最终创建了自己的函数来调用 std::stoi() 只有当整个字符串值是一个数字,否则,抛出一个 invalid_argument 异常。

话虽如此,我想知道为什么它是这样设计的,或者我不明白它是如何完全工作的。如果我要不断得到这样的惊喜,我宁愿不继续使用它。

更新:我检查了 cppreference.com 的文档,但我没有足够的经验来完全理解它。我试图对 std::stoi 定义进行逆向工程,但发现它远远超出了我的经验水平。我发布这个问题的目的是让其他人了解它的功能和了解细节的愿望。

【问题讨论】:

  • 您是否考虑过查阅文档?
  • 那是文档。如果你不能理解它,请更加努力。如果无法理解所提供的文档,您将在这项业务中一无所获,并且您肯定会“不断获得惊喜”,直到您克服这一困难。但我没有看到任何关于“尽可能多的字符来形成有效的 base-n(其中 n=base)整数表示并将它们转换为整数值”的任何不清楚的地方,这完全回答了你的问题。
  • 文档明确指出,它需要尽可能多的指定基数中的数字字符。 , 不是任何基数中的数字,所以它停在那里。你的惊讶是无法理解的。
  • @ProfounDisputes 我知道,但如果你看过这个例子,你就不会对函数表现出的行为感到惊讶
  • 我根本没有使用任何缩写,并且您引用的文档中没有任何内容超出任何称职的程序员。这里的问题不是这样,这是您对标准文档的难以理解的困惑。您将不得不克服这一点,而在线/交互式资源不是解决问题的方法。您不必在这里就已经在您已经找到的地方记录的基本内容提出问题。

标签: c++ string int invalid-argument


【解决方案1】:

根据C++标准(N4296),

§ 21.5

21.5 数值转换 [string.conversions]

  1. 效果:前两个函数调用strtol(str.c_str(), ptr, base),后三个函数 分别致电strtoul(str.c_str(), ptr, base)strtoll(str.c_str(), ptr, base)strtoull( str.c_str(), ptr, base)。每个函数都返回转换后的结果(如果有)。论据 ptr 指定一个指向函数内部对象的指针,该函数用于确定什么 存储在*idx。如果函数没有抛出异常并且idx != 0,函数存储在 *idx str 的第一个未转换元素的索引。
  2. 返回:转换后的结果。
  3. 抛出: invalid_argument 如果strtolstrtoulstrtollstrtoull 报告没有转化 可以执行。如果 strtolstrtoulstrtollstrtoullerrno 设置为 ERANGE,或者如果转换后的值超出了返回类型的可表示值范围。

strtol 是什么?

§ 21.8

21.8 空终止序列实用程序 [c.strings]

  1. 74、75、76、77、78 和 79 描述标题 <cctype><cwctype><cstring><cwchar>@987654345 @ (字符转换)和<cuchar>
  2. 这些头文件的内容应与标准 C 库头文件相同 <ctype.h>, <wctype.h>, <string.h><wchar.h><stdlib.h> 以及 C Unicode TR 标头 <uchar.h>,分别带有 以下修改:

表 78 - 标题 <cstdlib> 概要

类型名称
宏: MB_CUR_MAX
函数:
atof mblen strtof strtoul
atoi mbtowc strtol strtoull
atol mbstowcs strtold wctomb atoll strtod strtoll wcstombs

Standard C Library是什么意思?

§ 1.2

1.2 规范性参考文献 [intro.refs]

  1. 以下参考文件对于本文件的应用是必不可少的。对于过时的参考资料, 仅引用的版本适用。对于未注明日期的参考文献,参考文件的最新版本 (包括任何修改)适用。

    (1.3) — ISO/IEC 9899:1999,编程语言 — C
    (1.4) — ISO/IEC 9899:1999/Cor.1:2001(E),编程语言 — C,技术勘误 1
    (1.5) — ISO/IEC 9899:1999/Cor.2:2004(E),编程语言 — C,技术勘误 2

  2. ISO/IEC 9899:1999 第 7 条和 ISO/IEC 9899:1999/Cor.1:2001 第 7 条中描述的库 ISO/IEC 9899:1999/Cor.2:2003 的第 7 条以下称为 C 标准库。1

所以,我们需要关注 C99 标准。

根据C99标准(N1124)

§7.20.1.4

7.20.1.4 strtol、strtoll、strtoul 和 strtoull 函数

  1. 说明
    strtolstrtollstrtoulstrtoull函数nptr所指向的字符串的初始部分转换为long intlong long intunsigned long int ,和unsigned long long int 表示,分别。首先,他们将输入字符串分解为三个部分:一个初始的,可能为空的,序列 空白字符(由isspace 函数指定),一个类似于整数的主题序列,以由base 的值确定的某个基数表示,以及一个由一个或多个无法识别的字符组成的最终字符串,包括终止输入字符串的空字符。然后,他们尝试将主题序列转换为整数,并返回结果
  2. 如果base 的值为零,则主题序列的预期形式是6.4.4.1 中描述的整数常量,前面可选加号或减号,但不包括整数后缀。如果 base 的值介于 2 和 36(含)之间,则主题序列的预期形式是表示整数的字母和数字序列,基数由 base 指定,前面可选加号或减号, 但不包括整数后缀。 a(或A)到z(或Z)的字母赋值为10到35;只允许赋值小于base 的字母和数字。如果 base 的值为 16,则字符 0x0X 可以选择在字母和数字序列之前,如果存在则在符号之后
  3. 主题序列被定义为最长的输入字符串的初始子序列,从第一个非空白字符开始,即预期形式。如果输入字符串为空或完全由空格组成,或者如果第一个非空格字符不是符号或允许的字母,则主题序列不包含字符 或数字。
  4. 如果主题序列具有预期的形式并且base 的值为零,则根据6.4.4.1 的规则,从第一位数字开始的字符序列被解释为整数常量。如果主题序列具有预期的形式,并且base 的值在 2 到 36 之间,则将其用作转换的基础,并为每个字母赋予上面给出的值。如果主题序列以减号开头,则转换产生的值被否定(在返回类型中)。指向最终字符串的指针存储在endptr 指向的对象中,前提是endptr 不是空指针。
  5. "C" 语言环境以外的其他语言环境中,可以接受其他特定于语言环境的主题序列形式。
  6. 如果主题序列为空或不具有预期形式,则不进行转换; nptr的值存储在endptr指向的对象中,前提是endptr不是空指针。
  7. 退货
    strtolstrtollstrtoulstrtoull 函数返回转换后的值(如果有)。 如果无法执行转换,则返回零如果正确的值超出可表示值的范围,则返回LONG_MINLONG_MAXLLONG_MINLLONG_MAXULONG_MAXULLONG_MAX(根据返回值的类型和符号(如果有),ERANGE的值存储在errno

现在我们需要再次关注 C++ 标准。

21.5 数值转换 [string.conversions]

  1. 抛出: invalid_argument 如果strtolstrtoulstrtollstrtoull 报告没有转化 可以执行。如果 strtolstrtoulstrtollstrtoullerrno 设置为,则抛出 out_of_range ERANGE,或者如果转换后的值超出了返回类型的可表示值范围。

现在你可以理解何时抛出invalid_argumentout_of_range 异常了,我希望。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-02-08
    • 1970-01-01
    • 2011-10-29
    • 1970-01-01
    • 1970-01-01
    • 2014-06-12
    相关资源
    最近更新 更多