std::string 浮动或加倍

Posted

技术标签:

【中文标题】std::string 浮动或加倍【英文标题】:std::string to float or double 【发布时间】:2009-06-18 13:15:58 【问题描述】:

我正在尝试将std::string 转换为float/double。 我试过了:

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

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

【问题讨论】:

克制过度设计十年前就已经发现的东西的冲动。 您确定输出正确吗?它不应该产生零 另外,你不需要转换 atof,它已经返回一个 double。 我确定。调试器显示 0。结果为 0。平台:Linux。 您确定安装了正确的语言环境吗?试试 "0,6" 或 setlocale(LC_NUMERIC, "C"); 【参考方案1】:
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会更快。

【讨论】:

boost::lexical_cast 正在流式传输。 我认为,您通常不能说它们会带来性能损失。想想当你有一个 cin >> num; 之前会发生什么。用户必须非常快速地输入(像 rly jon skeet 一样)才能注意到 lexical_cast 的毫秒数更慢 :) 就是说,我相信有些任务 lexical_cast 会降低性能 :) 对于这个解决方案,atof() 前面的 :: 是做什么的?它需要在那里? @ShaChris 因为我想确保使用全局命名空间中的 atof 函数。 取决于当前语言环境【参考方案2】:

标准库 (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>

【讨论】:

我喜欢这个解决方案,但它似乎只来自 C++11。所以在我的 SDK 上不可用。 很高兴知道 C++ 标准委员会添加了这个。 ostringstream 本身太长了,无法输入,更不用说使用 .. 对于浮点数(正如我在谷歌通过键入“c++ string to float”发现的问题中所问的那样),应该使用 std::stof。 请注意,这可能会引发异常:std::invalid_argument(如果转换失败)std::out_of_range(如果超出范围) 买家注意,取决于当前的语言环境。【参考方案3】:

词法转换非常好。

#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;

【讨论】:

谢谢,它可以工作。但对我来说这是一个问题:为什么我的代码不工作。 @Johannes Schaub:基于ADL,他还不如拥有,使用定义加上他实际使用的定义可能会将大量std元素带入范围。此外 lexical_cast 非常慢,所以我没有 +1。 boost::lexical_cast 的一个很好的特性是错误处理。如果转换失败,则抛出异常:try ... boost::lexical_cast ... catch (std::exception const&amp; err) //handle excpetion 更准确地说,使用catch ( boost::bad_lexical_cast const&amp; err )捕获异常。【参考方案4】:

你可以使用 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");

【讨论】:

嗯,所以你认为 boost::lexical_cast 的接口很糟糕,不是吗?看看 stefanB 的回答! Boost 也是如此。 @kirsche40 对于尚未依赖 Boost 的人来说,这似乎是一个不错的选择(与 Boost 链接只是为了将 std::string 转换为数字有点矫枉过正!) @JEan-Phillippe Jodiun 我回复了一条现已删除的评论,其中有人推荐了 Boost。我知道 Boost 在大多数情况下都是矫枉过正的。顺便说一句,一段时间以来,Boost 的使用仅限于“较新”的编译器。旧项目不能使用 Boost。例如,ASIO 严重依赖于 std::addressof 等 C++11 特性,这使得它对于 C++98/C++03 编译器完全没有价值。恕我直言,当项目开始时,Boost 的目的是为旧编译器版本提供新的“标准化”功能...... :-(【参考方案5】:

是的,有一个词法转换。使用 stringstream 和

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

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

  os << x;
  os >> ret;

  return ret;  

【讨论】:

【参考方案6】:

你可以使用 boost 词法转换:

#include <boost/lexical_cast.hpp>

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

注意:boost::lexical_cast 会抛出异常,所以当你传递无效值时你应该准备好处理它,尝试传递 string("xxx")

【讨论】:

【参考方案7】:

如果您不想拖入所有的 boost,请使用 strtod(3) from &lt;cstdlib&gt; - 它已经返回一个 double。

#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() 不起作用...你在什么平台/编译器上?

【讨论】:

使用字符串流不需要提升 您的方法也返回零。 Linux。【参考方案8】:

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

double s2f(string str)

 istringstream buffer(str);
 double temp;
 buffer >> temp;
 return temp;

它有效。

【讨论】:

【参考方案9】:
   double myAtof ( string &num)
      double tmp;
      sscanf ( num.c_str(), "%lf" , &tmp);
      return tmp;
   

【讨论】:

无效答案,你怎么知道num中存储的值实际上是一个有效的浮点数?你不检查 sscanf 的返回类型,似乎是一种 MS 编码风格。【参考方案10】:

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

【讨论】:

【参考方案11】:

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

std::from_chars 函数返回一个from_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 处理浮点类型。

【讨论】:

【参考方案12】:

这个答案是在你的 cmets 中备份 litb。我非常怀疑您只是没有正确显示结果。

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

【讨论】:

我没有使用 printf 查看结果...并且我使用该值来设置窗口不透明度,并且我的窗口是完全透明的,因此值为 0。【参考方案13】:

至于为什么atof() 在最初的问题中不起作用:它被转换为 double 的事实让我感到怀疑。如果没有#include &lt;stdlib.h&gt;,代码不应编译,但如果添加强制转换以解决编译警告,则atof() 未正确声明。如果编译器假定 atof() 返回一个 int,则强制转换它会解决转换警告,但它不会导致返回值被识别为双精度值。

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

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

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

【讨论】:

【参考方案14】:

您可以(暂时)将字符串保留为char[] 并使用sprintf(),而不是将Boost 拖入方程式。

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

【讨论】:

【参考方案15】:

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

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

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

【讨论】:

没有来源?我自己google了一下:boost.org/doc/libs/1_55_0/doc/html/boost_lexical_cast/…【参考方案16】:

我的问题:

    独立于语言环境的字符串加倍(小数分隔符始终为“.”) 字符串转换失败时的错误检测

我的解决方案(使用 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 ... 我花了很长时间才找到这个解决方案。而且我仍然觉得我对字符串本地化和其他东西了解不够......

【讨论】:

以上是关于std::string 浮动或加倍的主要内容,如果未能解决你的问题,请参考以下文章

web前端面试题系列:

IE下的双外边距浮动bug

浏览器兼容问题

浏览器兼容问题汇总

margin---bug

常见浏览器的兼容问题