将字符串转换为unsigned int会返回错误的结果

tmi*_*hty 19 c++ type-conversion

我有以下字符串:

sThis = "2154910440";

unsigned int iStart=atoi(sThis.c_str());
Run Code Online (Sandbox Code Playgroud)

但结果是

iStart = 2147483647
Run Code Online (Sandbox Code Playgroud)

有人看到我的错误吗?

Ben*_*ley 35

atoi将字符串转换为int.在您的系统上,a int为32位,其最大值为2147483647.您尝试转换的值超出此范围,因此返回值atoi未定义.我想,你的实现会int在这种情况下返回a的最大值.

您可以改为使用atoll,返回long long,保证至少为64位.或者您可以使用来自stoi/stol/stoll系列的函数或其未签名的对应函数,这些函数实际上会以异常的形式提供有关超出范围值(和无效值)的有用错误报告.

我个人喜欢boost::lexical_cast.即使它看起来有点麻烦,但它可以用于更一般的上下文中.您可以在模板中使用它,只需转发类型参数,而不必具有特化

  • @Kyle_the_hacker:嗯,这是2013年,所以除非他另有说法,否则我将继续在我的答案中假设. (18认同)
  • @JamesKanze:老实说,即使OP明确声明他不能使用C++ 11,我也不会遗漏C++ 11的信息.无论如何我确实提供了C++ 98/03替代方案,那么问题是什么? (9认同)
  • @BenjaminLindley哪种忽视现实. (3认同)
  • @tmighty:你的编译器对C++ 11有部分支持,你的标准库确实有我提到的函数系列. (2认同)

Ben*_*igt 10

您应该使用std::strtoul,找到<cstdlib>,为无符号数设计,范围更大,并更好地报告错误.

如果要将std::string输入和异常用于错误处理,请使用std::stoul.一个简短,高效的实施方案如下:

#include <string>
#include <stdexcept>
inline unsigned int stoui(const std::string& s)
{
    unsigned long lresult = stoul(s, 0, 10);
    unsigned int result = lresult;
    if (result != lresult) throw std::out_of_range();
    return result;
}
Run Code Online (Sandbox Code Playgroud)

这将比istringstream文化不变(因此在异常语言环境中运行时没有意外的行为更改),完全可移植以及使用第三个参数快得多,您可以支持不同的数字基础甚至执行检测0x0前缀.

但是unsigned int不一定大到足以保持你的价值,所以使用unsigned long,然后你将不需要上面的包装.


hel*_*922 7

atoi返回一个signed int,它在你的平台上的最大值为2^31-1.

你将结果分配给什么并不重要,它将受到返回类型的限制.

C++流可以读取无符号的整数.

std::istringstream reader(sThis);
unsigned int val;
reader >> val;
Run Code Online (Sandbox Code Playgroud)