近期开发的C++
程序遇到一个关于locale
的问题。程序在通过SSH
直接登录到root
用户后,运行程序会崩溃,而通过其他用户SSH
登录后,再切换到root
用户后,程序则运行正常。
1 | terminate called after throwing an instance of 'std::runtime_error' |
根据locale文档中的描述:
1 | std::locale::locale(const char * __s) [explicit] |
可以得知,指定的locale
不存在。
Google
上查到一般解决方案是设置环境变量LC_ALL=C
可以解决。
下面来看看问题出现的原因和这样解决的原因。
locale
在UNIX/Linux
上指的是一系列环境变量,它根据用户所使用的语言、国家或者地区、字符集等来设置系统的语言环境。应用程序可以根据这个设置来展示不同的语言信息。
locale
把所涉及到的使用习惯的各个方面分成12个大类, 每类都有独立的环境变量来设置。
可以使用locale
命令来展示相应的配置:
1 | [root@default ~]# locale |
上边结果显示的不只有12个独立的LC_*
环境变量,还有LC_ALL
和LANG
两个环境变量。
它们的生效优先级是:
1 | LC_ALL > LC_* > LANG |
也就是, LC_ALL
是强制设定,设置它之后可以覆盖其他变量内容。LANG
是默认值,其他值没有设置时,使用它做为默认值。
我们开头提到的问题原因看上去是指定的locale
不存在,而在不同的SSH
登录环境下表现却有所不同,因而可能是不同环境下默认的locale
不同。经过调研发现:
直接使用root
用户SSH
登录后,执行locale
命令:
1 | [root@default ~]# locale |
默认的locale
为zh_CN.UTF-8
。
而使用其他用户SSH
登录再切换为root
之后,执行locale
:
1 | [root@default ~]# locale |
默认的locale
为en_US.UTF-8
。
而通过locale
查找,这台服务器上确实没有zh_CN.UTF-8
的语言包:
1 | [root@default ~]# locale -a |grep zh_CN |
因而当启动我们应用程序的bash
的locale
为zh_CN.UTF-8
时,程序抛出了异常,而locale
为en_US.UTF-8
时则正常运行。
那么这两种情况下locale
的差异来源于哪里呢?经过调研发现,默认情况下,SSH
连接会设置目标服务的环境变量,可以在配置文件:/etc/ssh/ssh_config
中进行调整:
1 | Host * |
由于我本地MAC
电脑的locale
为zh_CN.UTF-8
, 因而使用root
建立SSH
连接后,目标服务器上该SSH
连接所运行的bash
的locale
被设置为zh_CN.UTF-8
, 而通过其他用户切换到root
, 则使用了root
的默认locale
:en_US.UTF-8
。
应用程序不能依赖所有执行环境都能正确配置好locale
, 因而我们需要在应用程序中自行指定好locale
。也就是我们文章开头所说的,设置环境变量LC_ALL
为C
。
locale: C
是一个特殊的locale
, 其他的locale
是用于向人类展示信息的,而C
表示computer
, 它是用于向计算机展示信息的。它的字符集是单字节的ASCII
。它在POSIX
兼容的系统上都存在,因而我们的程序设定locale
为C
后,彻底摆脱了运行环境的影响,可以解决文章开头的问题。
参考:
- https://gcc.gnu.org/onlinedocs/gcc-4.6.2/libstdc++/api/a00589.html#a268965d97cffcf472d2f0fa8b74aa1e2https://gcc.gnu.org/onlinedocs/gcc-4.6.2/libstdc++/api/a00589.html#a268965d97cffcf472d2f0fa8b74aa1e2
- https://www.tecmint.com/set-system-locales-in-linux/
- http://www.360doc.com/content/14/0103/13/10384031_342301450.shtml
- https://stackoverflow.com/questions/29609371/how-not-to-pass-the-locale-through-an-ssh-connection-command
- https://blog.csdn.net/kunyus/article/details/104628559
- https://unix.stackexchange.com/questions/87745/what-does-lc-all-c-do