Я получаю неожиданное поведение в моем текущем проекте.
Я использую библиотеку DICOM dcmtk
читать информацию из некоторых файлов dicom и Qt
показать изображения.
При извлечении информации мне приходится конвертировать поля формата<64-разрядное число с плавающей запятой> \<64 bit float> «(Dicom Tag PixelSpacing). Я разбил на 2 строки в» \ «и преобразовал строки в двойной. Пока что все работает отлично.
Ну, почти: всякий раз, когда я создаю QApplication
объект до Я конвертирую строки в двойники, это дает мне целые числа вместо двойных.
Код выглядит так:
// Faulty situation
Database db;
QApplication app(&argc, argv);
db.fill_from_source(source); // here i get ints instead of doubles
// Rearrange code and recompile:
Database db;
db.fill_from_source(source); // now it gets me doubles.
QApplication app(&argc, argv);
// The fill function looks like this (simplified)
void Database::fill_from_source(const Source& source){
string s = source.get_pixel_spacing_string();
vector<string> s2 = split(s, "\\");
// get the double, that should not be integers!
double a = stod(s2[0]);
double b = stod(s2[1]);
}
Меня еще больше смущает, что он работает, шагая по коду с использованием QtCreator и GDB. Однако когда я запускаю исполняемый файл, я снова получаю целые числа.
Так что я отследил проблему до stod
операция: я получаю правильные строки из файла DICOM, но после stod
числа после точки просто обрезаются. Такое же поведение с stdlib
«s strtod
Ли QApplication
распределение делает что-то с std::stod
функционировать? Поскольку все происходит во время выполнения, я не понимаю, как.
Замена stod
с QString::toDouble
решает проблему …
Я использую gcc version 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04.3), GNU ld (GNU Binutils for Ubuntu) 2.24
,
Другие зависимости кода включают Eigen3
, Boost.Python
, Код построен с использованием проекта CMake с QtCreator в качестве IDE.
Кто-нибудь знает, откуда эта проблема? Это ошибка Qt?
Будучи одним из разработчиков DCMTK, т.е. используемого вами набора инструментов DICOM, я удивляюсь, почему вы не извлекаете значения с плавающей запятой непосредственно из элемента данных DICOM «Pixel Spacing», я имею в виду вместо извлечения всей строки символов (включая обратную косую черту) разделитель), а затем преобразование его компонентов в отдельные числа с плавающей точкой. Таким образом, не будет никаких проблем с текущими настройками локали.
Кстати, из-за проблемы с настройками локали мы ввели нашу собственную независимую от локали OFStandard :: atof () вспомогательная функция 🙂
std::stod
поведение зависит от текущей установленной локали C.
В соответствии с cppreference:
Во время запуска программы эквивалент
std::setlocale(LC_ALL, "C");
выполняется до запуска любого пользовательского кода.
Как указано @peppe в комментариях, во время QApplication
строительство setlocale(LC_ALL, "");
вызывается на Unix, таким образом изменяя std::stod
,
Вы можете сохранить локаль и установить ее обратно следующим образом:
std::string backup(
// pass a null pointer to query the current C locale without modifying it
std::setlocale(LC_ALL, nullptr)
);
QApplication app(&argc, argv);
// restore the locale
std::setlocale(LC_ALL, backup.c_str());
РЕДАКТИРОВАТЬ:
Перечитав документацию для QCoreApplication, в подробном описании есть параграф о настройках локали:
В Unix / Linux Qt по умолчанию настроен на использование настроек локали системы. Это может вызвать конфликт при использовании функций POSIX, например, при преобразовании между типами данных, такими как числа с плавающей запятой и строки, поскольку нотация может отличаться в разных локалях. Чтобы обойти эту проблему, вызовите функцию POSIX
setlocale(LC_NUMERIC,"C")
сразу после инициализации QApplication, QGuiApplication или QCoreApplication для сброса языкового стандарта, используемого для форматирования чисел, в «C» -locale.
тем не мение @ J.Riesmeier предоставил интересный ответ как один из разработчиков DCMTK.