最近一个自己开发的曾经可以正常工作的 C++ 动态库在客户的docker linux 实例上常常报错
有时报: invalid or unsupported charset: UTF-8
有时报:invalide or unsupported charset:ANSI_x3.4-1968
有时报:std::locale::facet::_S_create_c_locale name not valid
下面是导致这种现象的一个例子:
用 locale 命令,看到的情况可能是这样的,
第一张图表示,LANG 被设定为 en_US.UTF-8, 但系统中没有这个字符集。第二张图表示系统中目前可以支持的字符集只有 C, C.utf8 和 POSIX。
解决的办法,是安装需要的字符集,并将系统中的LANG设定为该字符集。
例如:可以通过 安装 UTF-8 字符集,并将系统默认 locale 设定为 en_US.UTF-8 解决。
编辑存在的文件 /etc/local.gen 将其中的 en_US.UTF-8 注释符号去掉
运行 locale-gen
Generating locales (this might take a while)....
en_US.UTF-8 ... done
Generation complete
此时再运行 locale -a. 得到的结果是
$ locale -a
C
C.UTF-8
POSIX
en_US.utf8
这样就解决问题了。但以上操作需要 root 权限。
然而,有些客户有严格的操作规范,不允许修改系统配置。此时就需要分析我们自己的代码,看看到底是哪里导致了问题。调试代码发现,问题出在
std::locale::global(std::locale("").
combine<std::numpunct<char> >(std::locale::classic()));
其中的 std::local("")根据系统当前的locale设定来构建std::locale对象。由于设定的locale在系统中并不存在,就会报错
std::locale::facet::_S_create_c_locale name not valid
在我的项目中,解决的办法是将异常catch, 并将当前进程的默认 locale 设定为 std::locale::classic()
// 使用当前locale,但numpunct使用缺省的,因此不会在输出数字时加上千位分隔符
try {
std::locale::global(std::locale("").
combine<std::numpunct<char> >(std::locale::classic()));
} catch (std::exception &e) {
LOGMGR( WARN, e.what());
std::locale::global(std::locale::classic());
}
在近来的项目中,合理的方法当然是修正系统的配置错误,上述代码不过是在不允许修改系统配置的情况下不得已为之罢了。