为啥 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() 的行为?的主要内容,如果未能解决你的问题,请参考以下文章
在 Matplotlib 3.1.2 中使用 qt5agg 后端,get_backend() 会改变行为