2015-04-27 77 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',所以可能有區別。 –