为什么QCoreApplication在Unix / Linux上默认调用setlocale(LC_ALL,“”)?

我认为可以肯定地说,C语言环境被普遍认为是一个坏主意。

如果您必须考虑将区域设置设置为与"C"不同的任何内容,那么编写一个试图parsing或编写基于文本的机器格式(经常发生)的应用程序几乎是不可能的。 由于语言环境通常是每个进程(并且setlocale通常不是线程安全的),所以如果你正在编写一个库或者你有一个multithreading程序,那么即使执行setlocale(LC_ALL, "C")也是不安全的setlocale(LC_ALL, "C")东东。

现在,由于这些原因,规则通常是“避免setlocale ,period”; 但是由于QCoreApplication和派生类的特殊行为,我们过去曾多次被咬过, 该文件说:

在Unix / Linux上,Qt被configuration为默认使用系统区域设置。 这可能会导致在使用POSIX函数时发生冲突,例如,在数据types(如浮点数和string)之间进行转换时,由于语言环境中的符号可能不同。 为了解决这个问题,请在初始化QApplicationQCoreApplication后立即调用POSIX函数setlocale(LC_NUMERIC,"C") ,以将用于数字格式的区域设置重置为“C”区域。

这个行为在另一个问题上已经被描述了。 我的问题是:这个显然愚蠢的行为的基本原理是什么? 尤其是,Unix和Linux有什么特别之处,只能在这些平台上做出这样的决定?

(顺便说一下,如果我只是做setlocale(LC_ALL, "C");创buildQApplication之后,一切都会中断吗?如果没问题,为什么不删除setlocale(LC_ALL, "");

从通过@Phil Armstrong和我进行的Qt源代码(请参阅聊天记录 )的调查来看,似乎setlocale调用自版本1以来有几个原因:

  • XIM,至少在古代,没有正确地“获取”当前的地点,没有这样的电话。
  • 在Solaris上,它甚至使用默认的C语言环境崩溃。
  • 在Unix系统上,它被用来(在其他系统中,在一个复杂的后备游戏中)“嗅探”“系统字符集”(无论在Unix上是什么意思),从而能够在QString表示和“local “8位编码(这对文件路径特别重要)。

确实,它已经检查了LC_*环境变量,就像它处理QLocale ,但是我认为,如果应用程序明确地改变了它, nl_langinfo解码当前的LC_CTYPE可能是有用的(但是看看是否有明确的变化,它必须从系统默认开始)。

有趣的是,他们在setlocale(LC_ALL, "")之后立即执行了一个setlocale(LC_NUMERIC, "C") setlocale(LC_ALL, "") ,但是这在Qt 4.4中被删除了 。 这个决定的基本原理似乎在于老Qt错误追踪器的任务#132859(它在TrollTech,Nokia和QtSoftware.com之间移动,在消失之前没有留下任何痕迹,甚至在Wayback机器中 ),并且在两个 错误关于这个话题。 我认为关于这个话题的权威性答案在那里,但是我找不到恢复它的方法。

我的猜测是,它引入了微妙的错误,因为环境似乎是原始的,但实际上,除了LC_NUMERIC类别(这是最明显的)之外,它实际上被setlocale调用所感动。 可能他们删除了调用以使语言环境设置更明显,并使应用程序开发人员采取相应措施。

Qt调用setlocale(LC_ALL, "") ,因为这是正确的做法:从cat on的每个标准Unix程序调用setlocale(LC_ALL, "") 。 该调用的结果是程序语言环境设置为由用户指定的。 请参阅setlocale()手册页:

在主程序启动时,便携式“C”语言环境被选为默认。 一个程序可以通过调用以下方式将其移植到所有语言环境:

setlocale(LC_ALL, "");

程序初始化后…

既然Qt都生成了要被用户读取的文本,并且解析了用户生成的输入,否则拒绝让用户以自己的语言环境特定的方式与用户通信是非常不友好的。 因此调用setlocale()。

我希望用户友好是没有争议的! 当你尝试解析你的程序在不同语言环境下运行时创建的数据文件时,问题当然就来了。 很显然,如果你使用基于sscanf和朋友的分析器而不是特定的数据格式的基于特定文本的格式,那么这是一个数据损坏的处方,如果不考虑区域设置。 解决方法是a)使用一个真正的序列化库来处理这些东西,或者b)在写入和读取数据时将语言环境设置为特定的(“C”)。

如果线程安全是一个问题,那么在现代POSIX实现(或GNU libc版本> = 2.3的任何Linux系统,在这个时候几乎都是“所有这些”),您可以调用uselocale()所有I / O的本地语言环境。 或者,您可以调用通常函数的_l版本,将语言环境对象作为补充参数。

如果你调用setlocale(LC_ALL, "C");一切都会中断吗setlocale(LC_ALL, "C"); ? 不,但是正确的做法是让用户设置他们喜欢的语言环境,并将数据保存在指定格式中,或指定在运行时读取和写入数据的语言环境。

POSIX系统(包括你提到的Unix / Linux系统)的特殊之处在于操作系统接口和C接口是混在一起的。 C语言setlocale调用尤其会干扰操作系统。

在Windows上,相比之下,语言环境显式地是每线程属性( SetThreadLocale ),但更重要的是, GetNumberFormat等函数接受一个语言环境参数。

请注意,你的问题相当容易解决:当使用Qt时,使用Qt。 所以这意味着读取你的文本输入到一个QString ,处理它,然后写回来。