在 C++ 中使用 istringstream 进行字符串到双重转换的意外结果
Posted
技术标签:
【中文标题】在 C++ 中使用 istringstream 进行字符串到双重转换的意外结果【英文标题】:Unexpected results using istringstream for string to double conversion in C++ 【发布时间】:2009-11-08 23:11:59 【问题描述】:我目前正在尝试获取一个字符串 ("0.1") 并在 10.6 和 gcc4.2 的 Xcode 中使用 C++ 将其转换为双精度。
我正在使用从another question 中提取的函数,但是当我尝试使用该函数时,根据gdb 的输入是(字符串)“0.1”,但我的输出是(双)2.1220023981051542e-314。
这是我的 sn-p 直接复制出来的代码:
double strToDouble(std::string const &numberString)
istringstream inStream(numberString);
double doubleValue;
inStream >> doubleValue;
if(!(inStream && (inStream >> std::ws).eof()))
return 0.0;
return doubleValue;
;
我使用的是 C++ 而不是 Obj-C,因为它最终可能必须在 *nix 或 windows 机器上编译。
我天生就是一个 php 程序员,但是我需要一些数字运算来加快速度,所以我用编译语言来做。大学处理低级语言已经很久了=P。所以,如果有人有想法,将不胜感激......
德鲁·J·索恩。
完整代码:
#include <iostream>
#include <vector>
#include <string>
#include <sstream>
using namespace std;
/*
* @var delimiters the string to define a break by
* @var str the string to break
* @var tokens where to store the broken string parts.
*/
void explode(const string& delimiters, const string& str, vector<string>& tokens)
// Skip delimiters at beginning.
string::size_type lastPos = str.find_first_not_of(delimiters, 0);
// Find first "non-delimiter".
string::size_type pos = str.find_first_of(delimiters, lastPos);
while (string::npos != pos || string::npos != lastPos)
// Found a token, add it to the vector.
tokens.push_back(str.substr(lastPos, pos - lastPos));
// Skip delimiters. Note the "not_of"
lastPos = str.find_first_not_of(delimiters, pos);
// Find next "non-delimiter"
pos = str.find_first_of(delimiters, lastPos);
;
/*
* @var numberString double to be converted as a string.
*/
double strToDouble(std::string const &numberString)
istringstream inStream(numberString);
double doubleValue;
inStream >> doubleValue;
if(!(inStream && (inStream >> std::ws).eof()))
return 0.0;
return doubleValue;
;
class Cluster
private:
vector<double> latStore;
vector<double> lngStore;
public:
Cluster(int,string,string);
;
/*
* @var latString a comma seperated list of doubles for the latitudes.
* @var lngString a comma separated list of doubles for the longitudes.
*/
Cluster::Cluster(int newLocationLength, string latString, string lngString)
// mark our vectors
vector<string> latStoreString;
vector<string> lngStoreString;
// Explode our input strings.
explode(",", latString, latStoreString);
explode(",", lngString, lngStoreString);
for( int i = 0; i < latStoreString.size(); i++)
// Grab the latitude and store it.
string tempLat = latStoreString[i];
double latDouble = strToDouble(tempLat);
latStore.push_back( strToDouble(tempLat) );
// Grab the longitude and store it.
string tempLng = lngStoreString[i];
lngStore.push_back( strToDouble(tempLng) );
int main (int argc, char * const argv[])
Cluster *rect = new Cluster("0.1,0.4","0.1,0.4");
return 0;
【问题讨论】:
奇数。当我针对 10.6 Debug 运行此代码时,我得到了从 if 检查返回的 0.0。如果我编译 10.6 Release,一切正常。以 10.5 为目标适用于 Debug 和 Release。不知道是什么问题。 太棒了。谢谢安东尼。当我将其更改为 10.5 时,它在这里工作。我什至从来没有想过。 10.5 是然后。如果你把它作为答案,我可以标记它是正确的,你可以获得更多的 BrowniePoints™。 =P 很高兴它能让你跑步。问题的原因似乎如 cdespinosa 的回答所示。我会将其标记为已接受的答案。 【参考方案1】:这可能是由 STL 调试模式引起的。在目标的预处理器宏构建设置中删除 _GLIBCXX_DEBUG 宏。
C++ Debug builds broke in Snow Leopard X-Code
【讨论】:
【参考方案2】:为什么不使用 atof() 代替呢? link
【讨论】:
我查看了 atof,但后来我必须使用 c 字符串,而不是字符串对象。在字符串到双精度转换之后,双精度被转储回向量并使用 char* 和字符串似乎使水变得浑浊。所以我猜......“我可以使用 char* 和向量吗?”是另一个问题... 你可以使用你的字符串对象并调用 .c_str() 来传递给 atof。【参考方案3】:我看不出您的代码片段有什么问题。你能显示你用来输出结果的代码
【讨论】:
【参考方案4】:正如 Myles 所建议的, atof() 可能更简单。您可以通过调用 c_str() 成员函数将字符串对象转换为 c 字符串:
double result = atof(inputString.c_str()); // 0.0 if a double couldn't be read
这里有更多信息:http://www.cplusplus.com/reference/clibrary/cstdlib/atof/
【讨论】:
【参考方案5】:#include <iostream>
#include <sstream>
double strToDouble(std::string const &numberString)
std::istringstream inStream(numberString);
double doubleValue;
std::cout << doubleValue << '\n';
inStream >> doubleValue;
if(!(inStream && (inStream >> std::ws).eof()))
return 0.0;
return doubleValue;
;
int main()
std::cout << strToDouble("0.1") << '\n';
return 0;
上面的代码给了我以下输出: -2.36907e-39 0.1
你是不是偶然在返回之前检查了 doubleValue 的值?
Cluster::Cluster(string latString, string lngString)
// mark our vectors
vector<string> latStoreString;
vector<string> lngStoreString;
// Explode our input strings.
explode(",", latString, latStoreString);
explode(",", lngString, lngStoreString);
for( int i = 0; i < latStoreString.size(); i++)
// Grab the latitude and store it.
string tempLat = latStoreString[i];
std::cout << "tempLat=" << tempLat << '\n';
double latDouble = strToDouble(tempLat);
std::cout << "latDouble=" << latDouble << '\n';
latStore.push_back( strToDouble(tempLat) );
// Grab the longitude and store it.
string tempLng = lngStoreString[i];
lngStore.push_back( strToDouble(tempLng) );
int main (int argc, char * const argv[])
Cluster *rect = new Cluster("0.1,0.4","0.1,0.4");
return 0;
输出: tempLat=0.1 latDouble=0.1 tempLat=0.4 latDouble=0.4
你能用这些修改运行代码吗(你没有在 ctor 中使用 int 参数,所以我只是删除了它)。我还使用 valgrind 运行了您的代码,没有出现错误(只有内存泄漏)。
【讨论】:
忘了提及编译器信息:g++ (Gentoo 4.3.4 p1.0, pie-10.1.5) 4.3.4 ...当我运行该代码时,我得到:6.95322e-310 0 现在我真的很困惑。 当我将其作为 10.6 运行时(请参阅对问题的评论),它可以工作,但作为 10.5,它仍然会吐出 0。我认为这是我的 IDE 的错误。 只是为了好玩,您可以尝试使用终端进行编译吗?可以将错误追溯到传递给 g++ 的特定参数。 有趣... 192-168-1-100:桌面绘制$ g++ -o test -isysroot /Developer/SDKs/MacOSX10.6.sdk main.cpp 192-168-1-100:桌面绘制$ ./test tempLat=0.1 latDouble=0.1 tempLat=0.4 latDouble=0.4 和 XCode 在下一条消息中...【参考方案6】:看起来您没有得到关于您的实施问题的答案。其他人建议使用 atof()。如果您想在实现中解决问题,请查看以下代码。不要使用vector to explode方法,而是放置vector以避免冗余代码。我也更改了 strToDouble 中的代码。
void explode(const string& delimiters, const string& str, vector<double>& tokens)
// Skip delimiters at beginning.
string::size_type lastPos = str.find_first_not_of(delimiters, 0);
// Find first "non-delimiter".
string::size_type pos = str.find_first_of(delimiters, lastPos);
while (string::npos != pos || string::npos != lastPos)
// Found a token, add it to the vector.
string temp = str.substr(lastPos, pos - lastPos);
tokens.push_back(strToDouble(temp));
// Skip delimiters. Note the "not_of"
lastPos = str.find_first_not_of(delimiters, pos);
// Find next "non-delimiter"
pos = str.find_first_of(delimiters, lastPos);
double strToDouble(std::string const &numberString)
istringstream inStream(numberString);
int pos = numberString.find_first_not_of("1234567890.", 0);
if (string::npos != pos)
return 0.0;
else
double doubleValue;
inStream >> doubleValue;
return doubleValue;
【讨论】:
以上是关于在 C++ 中使用 istringstream 进行字符串到双重转换的意外结果的主要内容,如果未能解决你的问题,请参考以下文章
c++中istringstream及ostringstream超详细说明
C++ 中的流类型,如何从 IstringStream 中读取?
C++ 使用 istringstream 将整数读取为无符号字符