整数到字符串的转换问题

Integer to string conversion issues

本文关键字:转换 问题 字符串 整数      更新时间:2023-10-16

我在使用Crypto++的Integer类时遇到了一些问题。我使用的是最新版本 5.6.2。

我正在尝试使用以下代码将整数转换为字符串:

CryptoPP::Integer i("12345678900987654321");
std::ostrstream oss;
oss << i;
std::string s(oss.str());
LOGDEBUG(oss.str()); // Pumps log to console and log file

输出似乎有额外的垃圾数据:

12345678900987654321.ÍÍÍÍÍÍÍÍÍÍÍýýýý««««««««îþîþ

当我直接输出到控制台时,我得到同样的事情:

std::cout << "Dec: " << i << std::endl; // Same result

此外,我无法获得精度或科学记数法。以下内容将输出相同的结果:

std::cout.precision(5); // Does nothing with CryptoPP::Integer
std::cout << "Dec: " << std::setprecision(1) << std::dec << i << std::endl;
std::cout << "Sci: " << std::setprecision(5) << std::scientific << i << std::endl;

最重要的是,足够大的数字打破了整个事情。

CryptoPP::Integer i("12345");
// Calculate i^16
for (int x = 0; x < 16; x++)
{
i *= i;
}
std::cout  << i << std::endl; // Will never finish

最终,我试图得到一些可以处理大Integer数字的东西,并且可以以科学记数法输出字符串。我在提取Integer库或根据需要对其进行修改方面没有问题,但我更喜欢使用稳定的代码。

我做错了什么,还是有办法让它正常工作?

我正在尝试使用以下代码将整数转换为字符串:

CryptoPP::Integer i("12345678900987654321");
std::ostrstream oss;
oss << i;
std::string s(oss.str());
LOGDEBUG(oss.str()); // Pumps log to console and log file

输出似乎有额外的垃圾数据:

12345678900987654321.ÍÍÍÍÍÍÍÍÍÍÍýýýý««««««««îþîþ

我无法在Visual Studio 2010上使用Crypto++ 5.6.2重现这一点。损坏的输出可能是其他问题的结果,而不是 Crypto++ 中的错误。如果您还没有这样做,我建议您尝试仅使用CryptoPP::Integerstd::cout在最小的程序中重现它,而不是其他应用程序代码,以消除所有其他可能的问题。如果它不能在微不足道的独立测试中工作(这会令人惊讶),则库的构建方式可能存在问题(例如,它可能使用与您的应用程序使用的不同C++运行时或编译器版本构建)。如果你的独立测试通过,你可以添加其他字符串操作、日志记录代码等,直到找到罪魁祸首。

我确实注意到您正在使用已弃用std::ostrstream。您可能希望改用std::ostringstream。这个堆栈溢出对"为什么 std::strstream 被弃用?"这个问题的回答可能会很有趣,甚至可能是该答案中提到的问题导致了你的问题。

此外,我无法获得精度或科学记数法。 以下内容将输出相同的结果:

std::cout.precision(5); // Does nothing with CryptoPP::Integer
std::cout << "Dec: " << std::setprecision(1) << std::dec << i << std::endl;
std::cout << "Sci: " << std::setprecision(5) << std::scientific << i << std::endl;

std::setprecisionstd::scientific修改浮点输入/输出。因此,对于intlong long等C++常规整数类型,这也行不通(但我可以看到,特别是对于像CryptoPP:Integer这样的任意长度整数,能够以指定的精度以科学记数法输出是有意义的)。

即使C++没有这样定义它,Crypto++的实现仍然需要注意这些标志。通过查看std::ostream& operator<<(std::ostream& out, const Integer &a)的 Crypto++ 实现,我可以看到它识别的唯一 iostream 标志是std::ios::octstd::ios::hex(分别用于八进制和十六进制格式的数字)。

如果你想要科学记数法,你必须自己格式化输出(或使用不同的库)。

最重要的是,足够大的数字打破了整个 东西。

CryptoPP::Integer i("12345");
// Calculate i^16
for (int x = 0; x < 16; x++)
{
i *= i;
}
std::cout  << i << std::endl; // Will never finish

这实际上将计算i^(2^16) = i^65536,而不是i^16,因为在每个循环中,您将i乘以其新的中间值,而不是其原始值。这段代码的实际结果将是 268,140 位长,所以我预计 Crypto++ 需要很长时间才能产生该输出。

以下是为产生正确结果而调整的代码:

CryptoPP::Integer i("12345");
CryptoPP::Integer i_to_16(1);
// Calculate i^16
for (int x = 0; x < 16; x++)
{
i_to_16 *= i;
}
std::cout << i_to_16 << std::endl;
LOGDEBUG(oss.str()); // Pumps log to console and log file

输出似乎有额外的垃圾数据:

12345678900987654321.ÍÍÍÍÍÍÍÍÍÍÍýýýý««««««««îþîþ

我怀疑你呈现的内容与你在现实生活中所做的略有简化。我相信这个问题与LOGDEBUGostringstream有关。我相信你输出的是char*的,而不是string的(尽管我们还没有看到你的记录器的代码)。

oss.str()返回的std::string是暂时的。所以这个:

LOGDEBUG(oss.str());

与此略有不同:

string t(oss.str());
LOGDEBUG(t);

当您打算使用它时,您应该始终在ostringstream中复制string。或者确保用法包含在一个语句中。

我发现的最好的方法是拥有:

// Note: reference, and the char* is used in one statement
void LOGDEBUG(const ostringstream& oss) {
cout << oss.str().c_str() << endl;
}

// Note: copy of the string below
void LOGDEBUG(string str) {
cout << str.c_str() << endl;
}

你甚至不能这样做(这个在生产中咬了我):

const char* msg = oss.str().c_str();
cout << msg << endl;

您无法这样做,因为从oss.str()返回的string是临时的。因此,语句执行后char*是垃圾。

解决方法如下:

const string t(oss.str());
const char* msg = t.c_str();
cout << msg << endl;

如果您在程序上运行Valgrind,那么您可能会得到与您使用ostringstreamstrings相关的看似无法解释的发现。

下面是一个类似的日志记录问题:字符串流临时 ostream 返回问题。另请参阅在单个语句中将临时字符串流转换为 c_str()。这是我遇到的一个:std:ostringstream 和 -std=c++11 的内存错误?


正如 Matt 在下面的评论中指出的那样,您应该使用ostringstream,而不是ostrstream。 自 C++98 年以来,ostrstream已被弃用,您在使用它时应该会收到警告。

所以改用这个:

#include <sstream>
...
std::ostringstream oss;
...

但我相信问题的根源在于您在LOGDEBUG函数或宏中使用std::string的方式。


您与 Integer 相关的其他问题已在 Softwariness 的回答和相关评论中处理。所以我不会再重复它们了。