【发布时间】:2015-11-12 09:58:52
【问题描述】:
考虑以下简约代码片段:
#include <stdio.h>
#include <errno.h>
#include <locale.h>
int main() {
const char *locale = setlocale(LC_ALL, "");
if (errno == ENOENT) {
printf("Locale %s unavailable.\n", locale ? locale : "<unknown>");
} else if (errno) {
printf("setlocale() failed: errno = %d\n", errno);
perror("setlocale() failed");
}
if (locale) {
printf("Current locale: %s\n", locale);
}
return errno;
}
这可以在许多 UNIX 机器(Solaris 8、Debian Linux 8、OpenBSD 5.8)上成功运行。不过也有一些例外。
根据manual page,如果进程环境(LC_ALL等)指定的locale不可用,setlocale返回NULL(即对应文件丢失,需要用localegen生成)或类似的工具)。测试表明在这种情况下errno 设置为ENOENT,但在 Debian 7 框之一上,setlocale 返回一个有效的非NULL 语言环境字符串和 将errno 设置为ENOENT。
Cygwin 表现出另一种奇怪的行为:对于每个单字节西里尔语言环境(ru_RU.CP1251、ru_RU.CP866、ru_RU.KOI8-R、ru_RU.ISO-8859-5),setlocale 返回正确的语言环境字符串 和 将 errno 设置为 EILSEQ。同时ru_RU.UTF-8不受影响。
如何进一步诊断上述病例?
【问题讨论】:
-
确保在调用
setlocale之前将errno设置为零 因为setlocale(就像所有POSIX 函数一样)如果成功,将保持errno不变. -
@FUZxxl:谢谢,忘记了,但是在
setlocale调用之前将errno设置为0 并不会改变整体情况:我仍然得到ENOENT和EILSEQ有效且可用语言环境。 -
@FUZxxl 这根本不是真的。 POSIX 明确表示:“未指定成功调用函数后的 errno 设置,除非该函数的描述指定不应修改 errno。”
setlocale并没有说不会改变errno,所以是允许的。 -
@Art 好吧,我好像在这方面被误导了。
标签: c posix locale errno setlocale