【问题标题】:How does this C++ code work?这个 C++ 代码是如何工作的?
【发布时间】:2012-11-14 03:44:36
【问题描述】:
enum STR2INT_ERROR { SUCCESS, OVERFLOW, UNDERFLOW, INCONVERTIBLE };

STR2INT_ERROR str2int (int &i, char const *s, int base = 0)
{
    char *end;
    long  l;
    errno = 0;
    l = strtol(s, &end, base);
    if ((errno == ERANGE && l == LONG_MAX) || l > INT_MAX) {
        return OVERFLOW;
    }
    if ((errno == ERANGE && l == LONG_MIN) || l < INT_MIN) {
        return UNDERFLOW;
    }
    if (*s == '\0' || *end != '\0') {
        return INCONVERTIBLE;
    }
    i = l;
    return SUCCESS;
}

我正在尝试编写一个程序,该程序可以将从文件中读取的字符串解析为整数值。在寻找执行此操作的方法时,我在 stackoverflow 帖子上找到了上面的这段代码:

How to parse a string to an int in C++?

但是,我无法理解它是如何工作的。 具体来说,如果 errno 被赋值为 0,程序员为什么要检查 errno == ERANGE? (ERANGE 是特殊值吗?)

其次,参数列表中的“char const *s”是什么意思?

PS:我对 C++ 编程不是很有经验。

【问题讨论】:

  • 1.因为strtol 可以改变errno。 2.阅读指针。 3. 更喜欢boost::lexical_cast 之类的东西,这是一个单行和可能的例外。
  • 这是 C。这样的标记可能会有所帮助。
  • @ahenderson 你是对的,但最初的问题被标记为 C++。此外,从char const* 的问题中,我收集到 OP 确实在尝试使用 C++,而不是 C。
  • @chris - 问题中的链接明确指出为什么不使用 boost::lexical_cast 并提出合理的观点。并不是我说不要使用它。
  • @DumbCoder,虽然我同意它背后的逻辑,但我知道只有一种情况它不能满足您的要求(确保读取了整个缓冲区),所以分开因此,这是一个非常有用的解决方案。

标签: c++ string parsing integer


【解决方案1】:

代码使用 strtol() 进行解析。这是一个标准的 C 库函数。您可以在其他地方找到有关 strtol() 的文档:

strtol() man page on die.net

errno 变量是标准 C 库定义的特殊全局变量。如果函数遇到错误,则将其设置为错误代码。因此,虽然在例程开始时将 errno 分配为零,但 strtol() 函数将在遇到错误时为 errno 分配一个新值。以下 if 语句检查上溢和下溢错误情况。

char const *s 参数是要解析的字符串。它是一个指向常量(只读)字符串的指针。按照惯例,字符串以 NULL 字节结尾。

【讨论】:

    【解决方案2】:

    每当我在 C++ 中完成字符串到 int 的转换时,我都会使用 atoi 方法。网上应该有很多适合你想做的例子

    【讨论】:

    • @Enigma:你应该永远使用atoiatoi 不提供处理错误输入的方法。 atoi 存在是出于遗留原因和编写快速代码草图。它在实际代码中是无用的。在 C++ 中,您有更好的方法来执行转换。但是如果你必须使用 C 风格的函数,它是 strto... group 并且只有 strto... group。
    • @AndreyT,您可以说 0 返回值是一种错误检查形式。这只是模棱两可,这就是为什么我说没有确定错误检查。
    • @chris:首先,0 确实模棱两可到了无用的地步。其次,atoi 有一个更大的问题——它在溢出时会产生未定义的行为。 sscanf 也存在同样的问题。同样,strto... 函数是执行转换的唯一可行方法。
    • @AndreyT 在 c++ 中进行转换的“更好方法”是什么?
    • @mahela007:例如,参见boost::lexical_cast 及其所基于的技术。
    【解决方案3】:

    这里的大部分特殊之处在于errno,而不是被比较的值。

    errno 是一个全局变量,一些(尤其是较旧的)库函数使用它来发出错误信号。您将 0 分配给它(这隐含意味着没有问题)。然后,如果它遇到问题,库函数可以为其分配一些非零值来告诉你想出错。

    在调用库函数后,您通常会检查 1) 它现在是否非零,以及 2) 如果是,它具有什么值。根据分配的值,您可以对出现的错误类型做出反应。

    不过,我应该补充一点,errno 的许多用途大多是不可移植的。 C 标准说 errno 存在,没有库函数将 0 分配给 errno,但仅此而已。它没有指定任何特定函数可以分配给它的非零值(嗯,它指定 some 函数分配的 some 非零值,但不限制对这些值或那些函数的赋值)。

    【讨论】:

    • “未指定”是什么意思? C 标准库规范(甚至 C89/90)确实声明 strtol(和该组的其他函数)在溢出时将 errno 设置为 ERANGE。它是在下溢的情况下由实现定义的,但在溢出时是有保证的。
    【解决方案4】:

    首先,这显然是一个伪装成C++的C程序。

    strtol 是标准 C 库中的一个函数,它执行实际工作。它的文档可以在那里访问:http://linux.die.net/man/3/strtol

    所有其他的只是初步和检查。

    errno 是 C 库中的一个特殊全局变量,可以由标准函数修改以设置适当的错误代码(是的,它是 C 遗留的,这不是线程安全的)。它的值可以设置为标准头文件“errno.h”中定义的值。

    【讨论】:

    • 你的最后一段是错误的。 const char* schar const* s 完全相同。你在想char* const s,它确实是一个指向可变数据的常量指针。
    • 评论旨在改进或讨论答案的各个方面。如果您同意您的最后一段是错误的,请删除它。无需在答案本身中解释这一点,也无需保留错误的部分作为记录(如果有人感兴趣,这就是答案历史的用途)。
    【解决方案5】:

    errno 是库提供的全局变量,strtol(以及其他库函数)使用它来指示错误情况。在上面的代码中,strtol 可以在用户设置为0 后更改errnoERANGE 确实是标准库提供的命名常量,代表strtol 用来表示超出范围错误的一些特殊值。

    您的char const *s 问题太模糊。你具体有什么不明白的? const 部分表示str2int 内的用户代码将不允许修改s 指向的字符串。编译器将尽最大努力防止对s 指向的字符串进行任何修改(或可能修改)操作。

    【讨论】:

      猜你喜欢
      • 2010-12-13
      • 2013-07-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-09
      • 2013-04-23
      • 2015-04-09
      相关资源
      最近更新 更多