2015-04-27 6 views
1

У меня возникли проблемы с классом Integer Crypto ++. Я использую последнюю версию, 5.6.2.Целое число для преобразования строк

Я пытаюсь преобразовать 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.ÍÍÍÍÍÍÍÍÍÍÍýýýý««««««««îþîþ 

я получаю то же самое, когда я выход напрямую на консоль:

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 или ее модификацией по мере необходимости, но я бы предпочел работать со стабильным кодом.

Я делаю что-то неправильно, или есть способ, которым я могу заставить это работать правильно?

+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))' *. См. Комментарии в [Целочисленный заголовочный файл] (http://www.cryptopp.com/docs/ref/integer_8h_source.html). Это ужасно большое число, даже для криптографии. Возможно, вам следует перейти в библиотеку, которая обеспечивает целочисленное целое, например [GNU's Multiprecision Integer] (https://gmplib.org/) (gmp). – jww

ответ

2

Я пытаюсь преобразовать 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.ÍÍÍÍÍÍÍÍÍÍÍýýýý««««««««îþîþ 

Я не могу воспроизвести это с Crypto ++ 5.6.2 в Visual Studio 2010. Поврежденный вывод, скорее всего, является результатом какой-то другой проблемы, а не ошибки в Crypto ++. Если вы еще этого не сделали, я предлагаю попытаться воспроизвести это в минимальной программе, используя CryptoPP::Integer и std::cout, и ни один из ваших других кодов приложений, чтобы устранить все другие возможные проблемы. Если он не работает в тривиальном автономном тесте (что было бы удивительно), могут возникнуть проблемы с тем, как была построена библиотека (например, возможно, она была построена с использованием другой версии C++ или версии компилятора из того, что использует ваше приложение) , Если ваш автономный тест проходит, вы можете добавить другие строковые операции, код регистрации и т. Д., Пока не найдете виновника.

Я замечаю, что вы используете std::ostrstream, который устарел. Вы можете использовать std::ostringstream instead. This 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::setprecision и std::scientificmodify floating-point input/output.Таким образом, с обычными целыми типами в C++, например int или long long, это тоже не сработает (но я вижу, что особенно с целыми числами произвольной длины, такими как CryptoPP:Integer, возможность вывода в научной нотации с определенной точностью имела бы смысл).

Даже если C++ не определял его так, реализация Crypto ++ все равно должна была учитывать эти флаги. От взгляда на реализацию Crypto ++ std::ostream& operator<<(std::ostream& out, const Integer &a) я вижу, что единственными признаками iostream, которые он распознает, являются std::ios::oct и std::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; 
+0

* «Коррумпированный результат, скорее всего, является результатом некоторой другой проблемы, а не ошибки в Crypto ++.» * +1. «LOGDEBUG» был моим первым подозреваемым, пока он не заявил, что может воспроизвести «cout». – jww

+0

Это очень хорошая информация, спасибо! Я полностью упустил из виду, что большое количество вопросов, вы были правы в том, что я хотел взять его во власти 16. Я проведу эти испытания сегодня и попытаюсь изолировать проблему дальше. Любые идеи о точности/научной нотации? Кажется, я не могу найти документацию о том, является ли это поддержкой или где она должна быть реализована. – Thebluefish

+0

@ Thebluefish Обновленный ответ для решения проблемы точности/научной проблемы, но вкратце это не сработает. – softwariness

1
LOGDEBUG(oss.str()); // Pumps log to console and log file 

Выход, как представляется, имеют дополнительные данные мусора:

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

Я подозреваю, что вы представили незначительно упрощается от того, что вы делаете в реальной жизни. Я считаю, что проблема связана с LOGDEBUG и ostringstream. И я считаю, что вы выводили char*, а не string (хотя мы не видели код для ваших регистраторов).

std::string возвращение из oss.str() является временным. Так что это:

LOGDEBUG(oss.str()); 

ли slighty отличается от этого:

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; 

Вы не можете сделать это, потому что string вернулся с oss.str() является временным. Таким образом, char* не работает после выполнения инструкции.

Вот как это исправить:

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

Если запустить Valgrind на вашей программе, то вы, вероятно, получите то, что должно казаться, что необъяснимые находки, относящиеся к использованию ostringstream и strings.

Аналогичная проблема с регистрацией: 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. ostrstream был устаревшим с C++ 98, и вы должны были получить предупреждение при его использовании.

Так что используйте вместо этого:

#include <sstream> 
... 

std::ostringstream oss; 
... 

Но я считаю, что корень проблемы заключается в том, как вы используете std::string в LOGDEBUG функции или макро.


Другие вопросы, связанные с Integer, были обработаны в ответе Softwariness и связанных комментариях. Поэтому я не буду снова их перефразировать.

+1

'oss.str()' и 'string (oss.str())' должны вести себя одинаково –

+0

Спасибо @Matt. Я не был уверен, что это изменит ситуацию. Я действительно видел, что GCC создает плохой код с Crypto ++. Плохой код, связанный с планированием деструкторов. Это было больше, и исправление заключалось в том, чтобы вы * не * использовали анонимные объявления. – jww

+1

На самом деле я беру это обратно: OP использует 'ostrstream', а не' ostringstream', поэтому может быть разница. –

Смежные вопросы