近期开发的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