为什么我不能使用 atof 将 std::string 转换为 double?

Why can't I convert a std::string to double using atof?

提问人:Max Frai 提问时间:6/18/2009 最后编辑:Jan SchultkeMax Frai 更新时间:9/9/2023 访问量:345523

问:

我正在尝试转换为 . 我试过了:std::stringfloat/double

std::string num = "0.6";
double temp = (double)atof(num.c_str());

但它总是返回零。还有其他方法吗?

C++语言

评论

5赞 emvee 6/18/2009
抵制过度设计十年前就已经想好的东西的冲动。
1赞 Johannes Schaub - litb 6/18/2009
你确定你输出正确吗?它不应该产生零
1赞 AlbertoPL 6/18/2009
此外,您不需要强制转换 ATOF,它已经返回双精度。
0赞 Max Frai 6/18/2009
我确定。调试器显示 0。结果是 0。平台:Linux。
13赞 Johannes Schaub - litb 6/18/2009
您确定安装了正确的区域设置吗?尝试 “0,6” 或 setlocale(LC_NUMERIC, “C”);

答:

11赞 DaClown 6/18/2009 #1

是的,有词汇演员表。使用 stringstream 和 << 运算符,或者使用 Boost,他们已经实现了它。

您自己的版本可能如下所示:

template<typename to, typename from>to lexical_cast(from const &x) {
  std::stringstream os;
  to ret;

  os << x;
  os >> ret;

  return ret;  
}
31赞 Bill Lynch 6/18/2009 #2

词汇演员表非常好。

#include <boost/lexical_cast.hpp>
#include <iostream>
#include <string>

using std::endl;
using std::cout;
using std::string;
using boost::lexical_cast;

int main() {
    string str = "0.6";
    double dub = lexical_cast<double>(str);
    cout << dub << endl;
}

评论

0赞 Max Frai 6/18/2009
谢谢,它有效..但这对我来说是一个问题:为什么我的代码不起作用。
2赞 3/11/2011
@Johannes Schaub:基于ADL,他可能已经有了,使用定义加上他实际使用的定义可能会将大量的std元素纳入范围。此外,lexical_cast速度非常慢,所以我没有+1。
0赞 Semjon Mössinger 5/9/2016
boost::lexical_cast 的一个很好的功能是错误处理。如果转换失败,则会引发异常:try { ... boost::lexical_cast ... } catch (std::exception const& err) { //handle excpetion }
0赞 Semjon Mössinger 5/9/2016
更准确地说,是用于捕获异常。catch ( boost::bad_lexical_cast const& err )
7赞 stefanB 6/18/2009 #3

您可以使用增强词法转换:

#include <boost/lexical_cast.hpp>

string v("0.6");
double dd = boost::lexical_cast<double>(v);
cout << dd << endl;

注意:boost::lexical_cast抛出异常,因此您应该准备好在传递无效值时处理它,请尝试传递string(“xxx”)

8赞 emvee 6/18/2009 #4

如果您不想拖入所有 boost,请使用 from - 它已经返回双精度。strtod(3)<cstdlib>

#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>

using namespace std;

int main()  {
    std::string  num = "0.6";
    double temp = ::strtod(num.c_str(), 0);

    cout << num << " " << temp << endl;
    return 0;
}

输出:

$ g++ -o s s.cc
$ ./s
0.6 0.6
$

为什么 atof() 不起作用......您使用的是哪个平台/编译器?

评论

0赞 jalf 6/18/2009
使用字符串流不需要提升
0赞 Max Frai 6/18/2009
您的方法也返回零。Linux的。
141赞 TimW 6/18/2009 #5
std::string num = "0.6";
double temp = ::atof(num.c_str());

对我来说,将字符串转换为双精度是一种有效的 C++ 语法。

您可以使用 stringstream 或 boost::lexical_cast 来做到这一点,但这些都会降低性能。


啊哈哈,你有一个Qt项目......

QString winOpacity("0.6");
double temp = winOpacity.toDouble();

额外注意:
如果输入数据是 ,会更快。
const char*QByteArray::toDouble

评论

7赞 TimW 6/18/2009
boost::lexical_cast 正在流式传输。
2赞 Johannes Schaub - litb 6/18/2009
我认为,你不能说它们会带来性能损失。想想在它之前你有一个 cin >> num; 时会发生什么;用户必须非常快速地输入(像 jon skeet 一样)才能注意到lexical_cast慢的毫秒:)也就是说,我相信有些任务lexical_cast会占用太多的性能:)
3赞 sivabudh 2/17/2010
对于这个解决方案,atof() 前面的 :: 有什么作用?它需要什么?
4赞 TimW 2/17/2010
@ShaChris 因为我想确保我使用全局命名空间中的 atof 函数。
2赞 nmr 1/21/2017
取决于当前区域设置
14赞 Gustavo Muenz 6/18/2009 #6

您可以使用 std::stringstream:

   #include <sstream>
   #include <string>
   template<typename T>
   T StringToNumber(const std::string& numberAsString)
   {
      T valor;

      std::stringstream stream(numberAsString);
      stream >> valor;
      if (stream.fail()) {
         std::runtime_error e(numberAsString);
         throw e;
      }
      return valor;
   }

用法:

double number= StringToNumber<double>("0.6");

评论

0赞 kirsche40 2/21/2014
嗯,所以你认为 boost::lexical_cast 的界面很糟糕,不是吗?看看stefanB的回答!Boost 也是如此。
0赞 Jean-Philippe Jodoin 7/23/2014
@kirsche40 对于还没有与 Boost 有依赖关系的人来说,这似乎是一个不错的选择(与 Boost 链接只是为了将 std::string 转换为数字有点矫枉过正!
0赞 kirsche40 7/23/2014
@JEan-Phillippe Jodiun 我回复了一条现已删除的评论,有人推荐了 Boost。我知道 Boost 大多数时候是矫枉过正的。顺便说一句,一段时间以来,Boost 的使用仅限于“较新”的编译器。较旧的项目无法使用 Boost。例如,ASIO 严重依赖 C++11 功能,如 std::addressof,这使得它对 C++98/C++03 编译器完全没有价值。恕我直言,当项目开始时,Boost 的目的是为较旧的编译器版本提供新的“标准化”功能...... :-(
1赞 T.E.D. 6/18/2009 #7

这个答案在您的评论中备份了 litb。我深深怀疑你只是没有正确显示结果。

我曾经发生过同样的事情。我花了一整天的时间试图弄清楚为什么我在 64 位 int 中得到了一个错误的值,结果发现 printf 忽略了第二个字节。你不能像 int 那样将 64 位值传递给 printf。

评论

0赞 Max Frai 6/18/2009
我没有使用 printf 查看结果......我使用该值来设置窗口不透明度,并且我的窗口是完全透明的,因此值为 0。
0赞 Chris Tonkinson 6/18/2009 #8

与其将 Boost 拖入等式中,不如将字符串(暂时)保留为 a 并使用 .char[]sprintf()

但是,当然,如果您仍然使用Boost,那真的不是什么大问题。

2赞 dpetek 6/18/2009 #9
   double myAtof ( string &num){
      double tmp;
      sscanf ( num.c_str(), "%lf" , &tmp);
      return tmp;
   }

评论

3赞 3/11/2011
无效的答案,你怎么知道存储在 num 中的值实际上是一个有效的浮点数?你不检查 sscanf 的返回类型,似乎是一种 MS 编码风格。
2赞 BSalita 3/3/2012 #10

C++ 11 方法是使用 std::stod 和 std::to_string。两者都适用于 Visual Studio 11。

1赞 Iain 4/10/2012 #11

至于为什么在原来的问题中不起作用:它被投射到双倍的事实让我怀疑。如果没有 ,代码就不应该编译,但如果添加强制转换是为了解决编译警告,则不会正确声明。如果编译器假定返回 int,则强制转换它将解决转换警告,但会导致返回值被识别为双精度值。atof()#include <stdlib.h>atof()atof()

#include <stdlib.h>
#include <string>

... 
  std::string num = "0.6";
  double temp = atof(num.c_str());

应该在没有警告的情况下工作。

131赞 ManuelSchneid3r 10/17/2012 #12

标准库 (C++11) 通过 std::stod 提供所需的功能:

std::string  s  = "0.6"
std::wstring ws = "0.7"
double d  = std::stod(s);
double dw = std::stod(ws);

通常,对于大多数其他基本类型,请参阅 <string>。C 字符串也有一些新功能。请参阅 <stdlib.h>

评论

4赞 pamplemousse_mk2 3/4/2013
我喜欢这个解决方案,但它似乎仅来自 C++11。所以在我的 SDK 上不可用。
0赞 bobobobo 1/24/2014
很高兴知道 C++ 标准委员会添加了这个。 本身就太长了,无法打出来,更不用说使用了.ostringstream
7赞 Étienne 7/25/2014
对于浮点数(正如我在谷歌上通过键入“c++ string to float”找到的问题中所问的那样),应该使用 std::stof。
1赞 Jason Doucette 2/13/2015
请注意,这可能会引发异常: std::invalid_argument(如果转换失败) std::out_of_range(如果超出范围)
4赞 nmr 1/21/2017
买家请注意,取决于当前的区域设置。
3赞 kenn 2/19/2013 #13

我在 Linux 中遇到了同样的问题

double s2f(string str)
{
 istringstream buffer(str);
 double temp;
 buffer >> temp;
 return temp;
}

它有效。

0赞 Zack Yezek 10/5/2013 #14

无论如何,您都不希望 Boost lexical_cast 用于字符串 <->浮点。该用例子集是唯一一个 boost 始终比旧函数差的集合 - 他们基本上将所有失败都集中在那里,因为他们自己的性能结果显示性能比使用 sscanf 和 printf 进行此类转换慢 20-25 倍。

你自己用谷歌搜索一下。boost::lexical_cast 可以处理大约 50 次转换,如果您排除涉及浮点 #s 的转换,它与明显的替代方案一样好或更好(额外的优势是所有这些操作都使用单个 API)。但是带上花车,就像泰坦尼克号在性能方面撞上冰山一样。

旧的专用 str->double 函数都可以在 30 毫秒(或更好)的时间内完成 10000 次解析。lexical_cast大约需要 650 毫秒才能完成相同的工作。

评论

0赞 Blake 10/29/2014
没有来源?我自己用谷歌搜索了一下:boost.org/doc/libs/1_55_0/doc/html/boost_lexical_cast/......
0赞 anhoppe 6/3/2015 #15

我的问题:

  1. 与区域设置无关的字符串为 double(小数点分隔符始终为 '.')
  2. 字符串转换失败时的错误检测

我的解决方案(使用 Windows 函数 _wcstod_l):

// string to convert. Note: decimal seperator is ',' here
std::wstring str = L"1,101";

// Use this for error detection
wchar_t* stopString;

// Create a locale for "C". Thus a '.' is expected as decimal separator
double dbl = _wcstod_l(str.c_str(), &stopString, _create_locale(LC_ALL, "C")); 

if (wcslen(stopString) != 0)
{
    // ... error handling ... we'll run into this because of the separator
}

HTH ...我花了很长时间才找到这个解决方案。而且我仍然觉得我对字符串本地化之类的了解还不够......

3赞 jignatius 2/14/2021 #16

在 C++17 中,您可以使用 std::from_chars,它是 和 的更轻量级更快的替代方案。它不涉及任何内存分配或查看语言环境,并且是非抛出的。std::stofstd::stod

该函数返回一个类型的值,该值基本上是一个包含两个字段的结构体:std::from_charsfrom_chars_result

struct from_chars_result {
    const char* ptr;
    std::errc ec;
};

通过检查,我们可以判断转换是否成功:ec

#include <iostream>
#include <charconv>

int main()
{
    const std::string str { "12345678901234.123456" };
    double value = 0.0;
    auto [p, ec] = std::from_chars(str.data(), str.data() + str.size(), value);
    if (ec != std::errc()) {
        std::cout << "Couldn't convert value";
    }
    
    return 0;
}

注意:你需要一个相当最新的编译器(例如gcc11)来处理浮点类型。std::from_chars