在使用std :: stod之前初始化QApplication的奇怪错误

时间:2016-12-21 18:16:37

标签: c++ qt c++11 stl dcmtk

我在当前项目中收到了意外行为。

我使用DICOM库dcmtk从某些dicom文件中读取信息,并使用Qt来显示图像。

在信息提取过程中,我必须转换格式为“< 64bit float> \< 64 bit float>”的字段(Dicom Tag PixelSpacing)。我在“\”处拆分为2个字符串,并将字符串转换为double。到目前为止,一切正常。

好吧,差不多:每当我在之前创建一个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的{​​{1}}

相同的行为

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.24Eigen3。代码是使用QakeCreator作为IDE的CMake项目构建的。

有谁知道这个问题来自哪里?这是一个Qt错误吗?

2 个答案:

答案 0 :(得分:3)

作为DCMTK开发人员之一,即您使用的DICOM工具包,我想知道为什么不直接从DICOM数据元素“Pixel Spacing”检索浮点值,我的意思是代替检索整个字符串(首先包括反斜杠分隔符,然后将其组件转换为单独的浮点数。这样,当前的语言环境设置就没有任何问题。

顺便说一句,由于区域设置问题,我们引入了自己的区域设置独立的OFStandard::atof()辅助函数: - )

答案 1 :(得分:2)

std::stod行为取决于当前安装的C语言环境。

根据cppreference

  

在程序启动期间,在运行任何用户代码之前执行等效的std::setlocale(LC_ALL, "C");

正如@peppe在评论中指出的那样,在QApplication期间,在Unix上调用构造setlocale(LC_ALL, "");,从而改变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函数时导致冲突,例如,在诸如浮点数和字符串之类的数据类型之间进行转换时,因为区域设置之间的符号可能不同。要解决此问题,请在初始化QApplication,QGuiApplication或QCoreApplication后立即调用POSIX函数setlocale(LC_NUMERIC,"C"),以将用于数字格式设置的区域设置重置为&#34; C&#34; -locale。

然而,@J.Riesmeier作为DCMTK开发人员之一提供了一个代理人的答案。