C++ 为什么QCoreApplication在Unix/Linux上默认调用`setlocale(LC_ALL,";)`呢?

C++ 为什么QCoreApplication在Unix/Linux上默认调用`setlocale(LC_ALL,";)`呢?,c++,linux,qt,localization,C++,Linux,Qt,Localization,我认为可以肯定地说,C语言环境被普遍认为是一个坏主意 如果您必须考虑将区域设置设置为与“C”不同的值,那么编写一个应用程序来尝试使用C标准库函数解析或编写基于文本的机器格式(这种情况经常发生)几乎是不可能的。由于区域设置通常是每个进程的(并且setlocale通常不是线程安全的),如果您正在编写库或您有一个多线程程序,那么即使执行setlocale(LC_ALL,“C”)并在完成任务后恢复它也不安全 现在,由于这些原因,规则通常是“避免setlocale,句号”;但是:QCoreApplicat

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

如果您必须考虑将区域设置设置为与
“C”
不同的值,那么编写一个应用程序来尝试使用C标准库函数解析或编写基于文本的机器格式(这种情况经常发生)几乎是不可能的。由于区域设置通常是每个进程的(并且
setlocale
通常不是线程安全的),如果您正在编写库或您有一个多线程程序,那么即使执行
setlocale(LC_ALL,“C”)
并在完成任务后恢复它也不安全

现在,由于这些原因,规则通常是“避免
setlocale
,句号”;但是:
QCoreApplication
和派生类的特殊行为在过去几次伤害了我们;报告说:

在Unix/Linux上,默认情况下,Qt配置为使用系统语言环境设置。这可能会在使用POSIX函数时导致冲突,例如,在数据类型(如浮点和字符串)之间转换时,因为表示法可能在不同的语言环境中有所不同。要解决此问题,请在初始化
QApplication
QCoreApplication
后立即调用POSIX函数
setlocale(LC_NUMERIC,“C”)
,将用于数字格式化的区域设置重置为“C”-区域设置

此行为已在中描述;我的问题是:这种明显愚蠢的行为的理由是什么?特别是,Unix和Linux有什么特别之处,只有在这些平台上才会做出这样的决定


(顺便说一句,如果我在创建
QApplication
之后只做
setlocale(LC_ALL,“C”)
,一切都会崩溃吗?如果可以的话,他们为什么不删除
setlocale(LC_ALL,”;
?)

POSIX系统(包括您提到的Unix/Linux系统)有什么特别之处就是OS接口和C接口混淆了。C
setlocale
调用尤其会干扰操作系统

相比之下,在Windows上,区域设置显式地是每个线程的属性(
SetThreadLocale
),但更重要的是,诸如
GetNumberFormat
之类的函数接受区域设置参数

注意,您的问题很容易解决:当使用Qt时,使用Qt。这意味着,处理它,然后将其写回。

Qt调用
setlocale(LC\u ALL,“”)
,因为这样做是正确的:来自
cat
的每个标准Unix程序向上调用
setlocale(LC\u ALL,”)
。该调用的结果是将程序语言环境设置为用户指定的语言环境。请参见setlocale()手册页:

主程序启动时,选择可移植的“C”语言环境 默认情况下。可通过调用以下命令使程序可移植到所有地区:

setlocale(LC_ALL,”)

程序初始化后

考虑到Qt既生成供用户读取的文本,又解析用户生成的输入,拒绝让用户以自己特定于语言环境的方式与用户通信是非常不友好的。因此调用setlocale()

我希望用户友好不会引起争议!当然,当您试图解析在不同语言环境下运行的程序创建的数据文件时,就会出现问题。显然,如果您使用基于sscanf和friends的解析器的特殊文本格式,而不是使用具有“真实”解析器的指定数据格式,那么如果不考虑区域设置,这将导致数据损坏。解决方案是a)使用真正的序列化库为您处理这些内容,或者b)在写入和读取数据时将语言环境设置为特定的(“C”可能)

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


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

通过@Phil Armstrong和我进行的Qt源代码调查(请参阅),由于以下几个原因,
setlocale
调用似乎自版本1起就存在:

  • XIM,至少在古代,没有这样的调用就不能正确地“获取”当前区域设置
  • 在Solaris上,它甚至使用默认的C语言环境崩溃
  • 在Unix系统上,它(在其他系统中,在一个复杂的回退游戏中)用于“嗅探”“系统字符集”(在Unix上是什么意思),从而能够在
    QString
    表示和“本地”8位编码之间进行转换(这对于文件路径尤其重要)
确实,它已经检查了
LC.*
环境变量,就像它检查
QLocale
一样,但是我认为如果应用程序显式地更改了当前的
LC.\u CTYPE
,那么让
nl.\u langinfo
解码它可能会很有用(但要查看是否有明确的更改,必须从系统默认值开始)

有趣的是,他们在
setlocale(LC#u ALL,”)
之后立即进行了
setlocale(LC#u NUMERIC,“C”)
,但这一决定的理由似乎在于旧Qt bugtracker的任务132859(它在TrollTech、Nokia和QtSoftware.com之间移动,然后消失,没有留下任何痕迹,甚至在网络中),并在关于t的