是std :: stoi实际上安全使用吗? [英] Is std::stoi actually safe to use?

查看:420
本文介绍了是std :: stoi实际上安全使用吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我和一个人谈论了 std :: stoi 的失败。简单地说,它在内部使用 std :: strtol ,并且抛出如果报告错误。根据他们, std :: strtol 不应该报告输入abcxyz的错误,导致 stoi 不会抛出 std :: invalid_argument

I had a lovely conversation with someone about the downfalls of std::stoi. To put it bluntly, it uses std::strtol internally, and throws if that reports an error. According to them, though, std::strtol shouldn't report an error for an input of "abcxyz", causing stoi not to throw std::invalid_argument.

首先,这里有两个程序在GCC上测试这些案例的行为:

strtol

stoi

First of all, here are two programs tested on GCC about the behaviours of these cases:
strtol
stoi

他们都在<$ c $上显示成功c>123且在abc上失败。

Both of them show success on "123" and failure on "abc".

我在标准中查看了更多信息:

I looked in the standard to pull more info:

§21.5

Throws: invalid_argument if strtol, strtoul, strtoll, or strtoull reports that  
no conversion could be performed. Throws out_of_range if the converted value is  
outside the range of representable values for the return type.

这总结了依赖 strtol 。现在, strtol ?我在C11草稿中找到了这个:

That sums up the behaviour of relying on strtol. Now what about strtol? I found this in the C11 draft:

§7.22.1.4

If the subject sequence is empty or does not have the expected form, no  
conversion is performed; the value of nptr is stored in the object  
pointed to by endptr, provided that endptr is not a null pointer.

鉴于传递abc,C标准规定指向字符串开头的 nptr 将存储在 endptr 中,指针传入。这似乎与测试一致。此外,应返回0,如下所示:

Given the situation of passing in "abc", the C standard dictates that nptr, which points to the beginning of the string, would be stored in endptr, the pointer passed in. This seems consistent with the test. Also, 0 should be returned, as stated by this:

§7.22.1.4

If no conversion could be performed, zero is returned.

前面的引用说不​​会执行转换,因此必须返回0.这些条件现在符合用 stoi 的C ++ 11标准抛出 std :: invalid_argument

The previous reference said that no conversion would be performed, so it must return 0. These conditions now comply with the C++11 standard for stoi throwing std::invalid_argument.

这对我来说很重要,因为我不想推荐 stoi 更好的替代其他方法的字符串到int转换,或者使用它自己,如果它的工作方式你期望的,如果它不捕获文本作为无效的转换。

The result of this matters to me because I don't want to go around recommending stoi as a better alternative to other methods of string to int conversion, or using it myself as if it worked the way you'd expect, if it doesn't catch text as an invalid conversion.

所有这一切后,我在某个地方出错了吗?在我看来,我有良好的证据,抛出这个异常。我的证明是有效的,或者是abc?不能保证抛出该异常, std :: stoi / p>

So after all of this, did I go wrong somewhere? It seems to me that I have good proof of this exception being thrown. Is my proof valid, or is std::stoi not guaranteed to throw that exception when given "abc"?

推荐答案

std :: stoi c $ c>abcxyz?



是的。

Does std::stoi throw an error on the input "abcxyz"?

Yes.

混淆可能来自 strtol 从不报告除了溢出之外的错误。它可以报告没有执行转换,但这在C标准中从不被称为错误条件。

I think your confusion may come from the fact that strtol never reports an error except on overflow. It can report that no conversion was performed, but this is never referred to as an error condition in the C standard.

strtol 类似地被所有三个C标准定义,我将给你无聊的细节,但它基本上定义了一个主题序列,它是对应于实际数字的输入字符串的子串。以下四个条件是等效的:

strtol is defined similarly by all three C standards, and I will spare you the boring details, but it basically defines a "subject sequence" that is a substring of the input string corresponding to the actual number. The following four conditions are equivalent:


  • 主题序列具有预期形式(以纯英语:it是数字)

  • 主题序列非空

  • 发生了转换

  • * endptr!= nptr (只有当 endptr 不是null时才有意义)

  • the subject sequence has the expected form (in plain English: it is a number)
  • the subject sequence is non-empty
  • a conversion has occurred
  • *endptr != nptr (this only makes sense when endptr is non-null)

当发生溢出时,仍然认为发生了转换。

When there is an overflow, the conversion is still said to have occurred.

现在,很明显,因为 abcxyz不包含数字,字符串abcxyz的主题序列必须为空,以便不能执行转换。以下C90 / C99 / C11程序将通过实验确认:

Now, it is quite clear that because "abcxyz" does not contain a number, the subject sequence of the string "abcxyz" must be empty, so that no conversion can be performed. The following C90/C99/C11 program will confirm it experimentally:

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

int main() {
    char *nptr = "abcxyz", *endptr[1];
    strtol(nptr, endptr, 0);
    if (*endptr == nptr)
        printf("No conversion could be performed.\n");
    return 0;
}

这意味着任何符合的实现 std ::当给予输入abcxyz 必须引发 invalid_argument >没有可选的基本参数。

This implies that any conformant implementation of std::stoi must throw invalid_argument when given the input "abcxyz" without an optional base argument.

否。你说话的人是正确的,当她说 std :: stoi 比执行完整检查更宽松 errno == 0&& ; end!= start&& std :: strtol 之后的 $ c>默默地从字符串中的第一个非数字字符开始除去所有字符。

No. The person you were talking to is correct when she says that std::stoi is more lenient than performing the full check errno == 0 && end != start && *end=='\0' after std::strtol, because std::stoi silently strips away all characters starting from the first non-numeric character in the string.

事实上,我的头顶部是本地转换行为的唯一语言有些像 std :: stoi 是Javascript,甚至然后你必须强制base 10与 parseInt(n,10)避免特殊情况的十六进制数字:

In fact off the top of my head the only language whose native conversion behaves somewhat like std::stoi is Javascript, and even then you have to force base 10 with parseInt(n, 10) to avoid the special case of hexadecimal numbers:

input      |  std::atoi       std::stoi      Javascript      full check 
===========+=============================================================
hello      |  0               error          error(NaN)      error      
0xygen     |  0               0              error(NaN)      error      
0x42       |  0               0              66              error      
42x0       |  42              42             42              error      
42         |  42              42             42              42         
-----------+-------------------------------------------------------------
languages  |  Perl, Ruby,     Javascript     Javascript      C#, Java,  
           |  PHP, C...       (base 10)                      Python...  

以及处理空格和冗余+号的语言之间的差异。

Note: there are also differences among languages in the handling of whitespace and redundant + signs.

我不知道任何内置函数,但 boost :: lexical_cast< int> 会做你想要的。它是特别严格的,因为它甚至拒绝周围的空格,不像Python的 int()函数。请注意,无效字符和溢出会导致相同的异常, boost :: bad_lexical_cast

I'm not aware of any built-in function that does this, but boost::lexical_cast<int> will do what you want. It is particularly strict since it even rejects surrounding whitespace, unlike Python's int() function. Note that invalid characters and overflows result in the same exception, boost::bad_lexical_cast.

#include <boost/lexical_cast.hpp>

int main() {
    std::string s = "42";
    try {
        int n = boost::lexical_cast<int>(s);
        std::cout << "n = " << n << std::endl;
    } catch (boost::bad_lexical_cast) {
        std::cout << "conversion failed" << std::endl;
    }
}

这篇关于是std :: stoi实际上安全使用吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆