2015-04-27 78 views
1

我遇到了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 

此外,我不能得到精度或科学no工作。以下内容将输出相同的结果:

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库或根据需要修改它的问题,但我宁愿使用稳定的代码。

我做错了什么,或者有没有办法让我的工作正常?

+1

显示LOGDEBUG的定义。听起来就像你在调用'printf'并传递从'ostrstream'返回的字符串对象而不是指向文本缓冲区的指针。由于没有进行任何调用来强制缓冲区被空终止,因此您可能会在文本之后看到垃圾。尝试'LOGDEBUG(oss.str()。c_str())' –

+0

坦率地说,LOGDEBUG在这里不是问题。正如我的帖子所指出的,std :: cout产生相同的输出。我可以完全删除我的Urho3D的东西(包括LOGDEBUG)和std :: cout仍然会产生相同的问题。 – Thebluefish

+0

*“除此之外,足够多的数字打破了整个事情” - 是的,这是记录的行为。确切的大小是*绝对值小于(256 ** sizeof(word))**(256 ** sizeof(int))* *。请参阅[Integer头文件](http://www.cryptopp.com/docs/ref/integer_8h_source.html)中的注释。即使是密码学,这个数字也是非常大的。也许你应该转向一个提供通用整数的库,如[GNU's Multiprecision Integer](https://gmplib.org/)(gmp)。 – jww

回答

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.ÍÍÍÍÍÍÍÍÍÍÍýýýý««««««««îþîþ 

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

我注意到,虽然您使用的已弃用的std::ostrstream。您可能需要使用std::ostringstream insteadThis Stack Overflow answer to the question "Why was std::strstream deprecated?"可能会引起人们的兴趣,甚至可能是这个答案中提到的问题在这里引起你的问题。

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

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::scientificmodify floating-point input/output。因此,使用C++中的常规整数类型(如intlong long),这也不起作用(但我可以看到,特别是使用任意长度的整数,例如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 

这将实际计算​​3210,不i^16,因为在每次循环你乘以i其新的中间值,而不是它原来的价值。这段代码的实际结果是268,140位数字,所以我期望它只是花费很长时间来生成该输出。

这里是调整,以产生正确的结果代码:

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; 
+0

*“损坏的输出可能是其他问题的结果,而不是Crypto ++中的错误。”* +1。 'LOGDEBUG'是我第一个犯罪嫌疑人,直到他说他可以用'cout'重现。 – jww

+0

这是非常好的信息,谢谢!我完全忽略了这个大数目的问题,你说得对,因为我想让它达到16的强度。我将在今晚测试这些问题,并尝试进一步隔离问题。关于精密/科学记数法的任何想法?我似乎无法找到任何有关这是支持还是需要实施的文档。 – Thebluefish

+0

@Thebluefish更新了解决精度/科学问题的答案,但总之不起作用。 – softwariness

1
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); 

你应该总是让string的副本在ostringstream当你打算使用它。或确保的使用是包含在一个声明中。

我发现最好的办法是让:

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

你不能这样做,因为stringoss.str()是暂时的。所以在语句执行后char*是垃圾。

这里是你如何解决这个问题:

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

如果您在程序运行Valgrind的,那么你可能会得到什么应该似乎与您使用的ostringstreamstrings不明原因的调查结果。

这里是一个类似的日志记录问题:stringstream temporary ostream return problem。另见Turning temporary stringstream to c_str() in single statement。这里是一个我经历:Memory Error with std:ostringstream and -std=c++11?


马特在评论中指出的下方,你应该使用ostringstream,而不是ostrstream。从C++ 98开始已弃用ostrstream,并且在使用它时应该得到警告。

所以用这个来代替:

#include <sstream> 
... 

std::ostringstream oss; 
... 

但我相信问题的根源是你在LOGDEBUG功能或宏使用std::string的方式。


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

+1

'oss.str()'和'string(oss.str())'应该表现相同 –

+0

Thanks @Matt。我不确定这是否会有所作为。我已经看到GCC使用Crypto ++生成不好的代码。坏代码与析构函数的调度有关。还有更多,修复是为了确保你不*使用匿名声明。 – jww

+1

实际上我回过头来看:OP使用'ostrstream',而不是'ostringstream',所以可能有区别。 –