为啥 Qt 会改变 sscanf() 的行为?

Posted

技术标签:

【中文标题】为啥 Qt 会改变 sscanf() 的行为?【英文标题】:Why does Qt change behaviour of sscanf()?为什么 Qt 会改变 sscanf() 的行为? 【发布时间】:2013-12-12 22:35:36 【问题描述】:

我注意到,Qt (4.8) 改变了sscanf() 的行为。没有 Qt sscanf() 照常工作,但有了它,它只需要本地化的字符串。

这是一个最小化的例子:


没有 Qt(纯 C++)

int main(int argc, char *argv[])

    float f;
    sscanf("0.83", "%f", &f);

    std::cout << f << "\t-->\t" << typeid("0.83").name() << std::endl;

    return 0;

输出:

0.83    -->     A5_c

(给定字符串是一个 5x char-array,结果正确)


使用 Qt

int main(int argc, char *argv[])

    /*
     * This breaks sscanf() for the whole (!) project
     * and linked libraries too!
     */
    QApplication(argc, argv);

    float f;
    sscanf("0.83", "%f", &f);

    std::cout << f << "\t-->\t" << typeid("0.83").name() << std::endl;

    return 0;

输出:

0       -->     A5_c

(给定字符串仍然是 5x char-array,但结果是错误的)


虽然0.83 失败,但使用0,83(我的语言环境格式)在 Qt 上可以正常工作 - 但在没有 Qt 的情况下会失败(默认行为)。如typeid() 所示,没有使用QString - 只有普通的旧 C(++) 字符数组。顺便说一句,std::string 也是如此。

除此之外,使用std::stringstream 可以正常工作:

std::stringstream ss;
ss << "0.83"; // But the value into the stream
ss >> f;      // Get a float out of it

结果:

0.83

问题来了: 为什么 char-array 字符串和 sscanf() 调用会受到 Qt 的影响?我理解为什么 QString 是本地化的,但打破sscanf()(以及可能的其他 stdio.h 函数)对我来说听起来很邪恶。

背景:我将一个(非 Qt)库(在代码深处包含 sscanf())链接到一个 Qt 项目。结果:这个项目中的一些代码失败了,而它在其他地方都可以工作......(花了一些时间找到原因......)

【问题讨论】:

感谢您的提问!我花了一段时间才发现问题。 【参考方案1】:

一般来说,如果您在标准库中获得与流或 I/O 操作有关的函数,那么它很可能会受到您的语言环境设置的影响。

sscanf 也是如此,在您的情况下,Qt 会覆盖您在使用默认 C/C++ 配置时通常会获得的默认 C locale

你应该使用

setlocale(LC_NUMERIC,"C")

在初始化您的 Qt 环境之后,在这种情况下是在 QApplication 之后。

https://qt-project.org/doc/qt-5/qcoreapplication.html#locale-settings

让事情回到你所期望的。

【讨论】:

我明白了......在某些情况下,如果默认设置语言环境,这可能是一件好事,但在我的情况下,这会导致 与 POSIX 函数发生冲突(如在您的链接中说)。但是,设置语言环境可以正常工作,并且另一方面不会破坏 gui 组件。感谢您的回答! 不,不要那样做。如果您使用由标准 C 库函数解析的基于特定文本的格式,只需在读取和写入保存的数据之前调用 uselocale(),然后再将其设置回用户区域设置。【参考方案2】:

我怀疑 QT 会根据您的系统区域设置自动设置区域设置。实际上有一个standard localization library。

设置 C 语言环境会更改一组函数的行为,列出 on this page。

但是请注意,C++ 流不会自动选择 C ​​语言环境,这就是您的 std::stringstream 行为正常的原因。

【讨论】:

非常好!我认为(字符串)流也会使用语言环境,所以这对我来说看起来很奇怪。那么使用这些流而不是例如使用这些流通常更安全吗? sscanf() 用于此类解析(不使用任何本地格式)? 如果需要,您可以随时检查 C 语言环境。老实说,我很少有处理本地化代码的经验,所以我不确定您可能会发现哪些陷阱。【参考方案3】:

Qt 正在调用 setlocale 来设置 C runtuime 以使用您的语言环境。您可以尝试使用 setlocale(LC_ALL, “C”);但我不确定这会如何影响 Qt 的其余部分。

【讨论】:

感谢您的提示!我刚刚检查了 gui 组件(如双旋转框),它们似乎保持其本地格式,而 sscanf() 工作(再次)。

以上是关于为啥 Qt 会改变 sscanf() 的行为?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 firebug 在调试时会改变网站的行为?

在 Matplotlib 3.1.2 中使用 qt5agg 后端,get_backend() 会改变行为

常量和编译时评估 - 为啥要改变这种行为

Ubuntu下用命令行运行QT程序的显示效果为啥跟双击程序的效果不一样?

为啥 QLineEdit Style 在聚焦时不改变?

为啥传递给函数的协议默认值不会改变,即使函数在子类化时会改变?