我认为可以肯定地说C语言环境被普遍认为是一个坏主意。
如果您必须考虑将区域设置设置为与"C"
不同的区域,那么编写一个尝试使用C标准库函数解析或编写基于文本的计算机格式(经常发生)的应用程序几乎是不可能的。由于语言环境通常是每个进程(并且setlocale
通常不是线程安全的),如果您正在编写库或者您有一个多线程程序,即使执行setlocale(LC_ALL, "C")
也不安全在做完你的东西之后恢复它。
现在,由于这些原因,规则通常是“避免setlocale
,期间&#34 ;; 但是:我们过去曾被QCoreApplication
和派生类的特殊行为多次咬过; documentation说:
在Unix / Linux上,Qt配置为默认使用系统区域设置。这可能会在使用POSIX函数时导致冲突,例如,在诸如浮点数和字符串之类的数据类型之间进行转换时,因为区域设置之间的符号可能不同。要解决此问题,请在初始化
setlocale(LC_NUMERIC,"C")
或QApplication
后立即调用POSIX函数QCoreApplication
,以将用于数字格式设置的区域设置重置为" C" -locale
another question中描述了此行为;我的问题是:这种看似愚蠢的行为的理由是什么?特别是,Unix和Linux的特殊之处只能在这些平台上做出这样的决定?
(顺便说一下,如果我在创建setlocale(LC_ALL, "C");
之后QApplication
执行setlocale(LC_ALL, "");
,一切都会中断吗?如果没问题,为什么他们不删除{{1}} ?)
答案 0 :(得分:7)
通过@Phil Armstrong和我进行的Qt源代码调查(参见the chat log),似乎{1}}调用自版本1以来就出现了以下几个原因:
setlocale
表示和"本地"之间进行转换。 8位编码(这对文件路径尤其重要)。确实它已经检查了QString
环境变量,就像LC_*
一样,但我认为让QLocale
解码当前可能是有用的nl_langinfo
如果应用程序显式更改了它(但要查看是否存在显式更改,则必须从系统默认值开始)。
有趣的是,他们在LC_CTYPE
之后立即 setlocale(LC_NUMERIC, "C")
,但this was removed in Qt 4.4。这个决定的理由似乎在于旧Qt bugtracker的任务#132859(它在TrollTech,诺基亚和QtSoftware.com之间移动而不会离开任何轨道,甚至在Wayback Machine中都没有),而且它&# 39;在two bugs中引用了有关此主题的内容。我认为关于这个主题的权威答案是存在的,但我找不到恢复它的方法。
我的猜测是它引入了微妙的错误,因为环境似乎原始,但事实上除了setlocale(LC_ALL, "")
类别之外的所有setlocale
调用都触及了它(这是最明显的);可能他们删除了调用以使语言环境设置更加明显,并让应用程序开发人员采取相应的行动。
答案 1 :(得分:4)
Qt调用setlocale(LC_ALL, "")
,因为这是正确的做法:来自cat
的每个标准Unix程序都在调用setlocale(LC_ALL, "")
。该调用的结果是程序区域设置被设置为用户指定的区域。请参阅setlocale()联机帮助页:
在启动主程序时,选择便携式“C”语言环境 作为默认值。通过调用:
,程序可以移植到所有语言环境
setlocale(LC_ALL, "");
程序初始化后......
鉴于Qt都生成要由用户读取的文本并解析用户生成的输入,拒绝让用户以他们自己的特定于语言环境的方式与用户通信将是非常不友好的。因此调用setlocale()。
我希望用户友好是没有争议的!当您尝试解析由在不同语言环境下运行的程序创建的数据文件时,问题就出现了。显然,如果您使用基于文本的ad-hoc格式与基于sscanf和朋友的解析器,而不是使用“真实”解析器的指定数据格式,那么如果不考虑区域设置。解决方案是:a)使用一个真正的序列化库来为你处理这些东西,或者b)在编写和读取数据时将语言环境设置为特定的东西(可能是“C”)。
如果线程安全是一个问题,那么在现代POSIX实现(或任何具有GNU libc版本> = 2.3的Linux系统,此时几乎都是“所有这些”),您可以调用{{1}为所有I / O设置线程本地语言环境。或者,您可以调用将语言环境对象作为补充参数的常用函数的uselocale()
版本。
如果你致电_l
,一切都会破裂吗?不,但正确的做法是让用户设置他们喜欢的语言环境,并以指定的格式保存数据,或者指定在运行时读取和写入数据的语言环境。
答案 2 :(得分:3)
POSIX系统(包括你提到的Unix / Linux系统)的特殊之处在于操作系统界面和C界面混杂在一起。特别是C setlocale
调用会干扰操作系统。
在Windows上,相比之下,语言环境显式是每线程属性(SetThreadLocale
),但更重要的是,GetNumberFormat
等函数接受语言环境参数。
请注意,您的问题很容易解决:使用Qt时,请使用Qt。这意味着reading your text input into a QString
,处理它,然后再写回来。