分享

【转】C/C 中locale的使用

 fisher60 2012-12-02

其声明如下:

#include <clocale>

char* setlocale(int category, const char* locale);

category:为locale分类,表达一种locale的领域方面,通常有下面这些预定义常量:

LC_ALL :               全部本地化信息

LC_COLLATE :     影响strcoll和strxfrm

LC_CTYPE :         影响字符处理函数和多行字符处理函数

LC_MONETRAY : 影响localeconv返回的货币格式化信息

LC_NUMERI C:     影响格式化输入输出字符中的小数点符号

LC_TIME :            影响strftime函数

其中 LC_ALL 表示所有其它locale分类的并集。

locale:为期望设定的locale名称字符串.

当 locale 为 NULL 时,函数只取回当前 locale 操作,通过返回值传出,并不改变当前 locale。

当 locale 为 "" 时,根据环境的设置来设定 locale,检测顺序是:环境变量 LC_ALL,每个单独的locale分类LC_*,最后是 LANG 变量。为了使程序可以根据环境来改变活动 locale,一般都在程序的初始化阶段加入下面代码:setlocale(LC_ALL, "")。

当C语言程序初始化时(刚进入到 main() 时),locale 被初始化为默认的 C locale,其采用的字符编码是所有本地 ANSI 字符集编码的公共部分,是用来书写C语言源程序的最小字符集(所以才起locale名叫:C)。当用 setlocale() 设置活动 locale 时,如果成功,会返回当前活动 locale 的全名称;如果失败,会返回 NULL。

setlocale():设置 locale

_get_current_locale():返回当前的 _locale_t 值。

lang[_country_region[.code_page]]:虽然形式与 glibc 的相同,当 Windows 的 locale 名并不符合 POSIX 的规范,比如采用 GBK 字符集的大陆中文,POSIX 的名字为:zh_CN.GBK,而在 Windows CRT 中要用:Chinese_People's Republic of China.936,

lang 字段的可用值参考:Language Strings

country_region 字段的可用值参考:Country/Region Strings

code_page 字段的可用值是 Windows 系统支持的代码页编号,参考:Code Page Identifiers

.code_page:可以直接使用代码页来设定 locale,而且可以使用 .OCP、.ACP 两个伪代码页,.OCP 表示从系统获得

NULL:取回当前 locale,不改变当前 locale。

setlocale() 的作用和使用示例

当向终端、控制台输出 wchar_t 类型的字符时,需要设置 setlocale(),因为通常终端、控制台环境自身是不支持 UCS 系列的字符集编码的,使用流操作函数时(如:printf()),在标准/RT库实现的内部会将 UCS 字符转换成合适的本地 ANSI 编码字符,转换的依据就是 setlocale() 设定的活动 locale,最后将结果字符序列传递给终端,对于来自终端的输入流这个过程刚好相反。

可以用重定向输出流到文件的方法验证上面的机制:无论是 Windows CRT、Linux glibc、Cygwin glibc,使用 wprintf() 打印 wchar_t 字符文本时,重定向到文件的内容总是 GBK、UTF-8 等本地 ANSI 编码,而不会是 UCS 编码。

下面是我写的一个使用 setlocale() 的示例:

#define LC_NAME_zh_CN_GBK       "zh_CN.GBK"

#define LC_NAME_zh_CN_UTF8      "zh_CN.UTF8"

#define LC_NAME_zh_CN_DEFAULT   "Chinese_People's Republic of China.GBK"

void print_current_loc();

int main(int argc, char* argv[]) {

    char* locname = NULL;

    const wchar_t* strzh = L"中文字符串";

    print_current_loc();

    // 使用指定的 locale

    locname = setlocale(LC_ALL, LC_NAME_zh_CN_DEFAULT);

    if (NULL == locname){

        printf("setlocale() with %s failed.\n", LC_NAME_zh_CN_DEFAULT);

    } else {

        printf("setlocale() with %s succeed.\n", LC_NAME_zh_CN_DEFAULT);

    }

    print_current_loc();

    wprintf(L"Zhong text is: %ls\n", strzh);

    // 使用运行环境中的 locale 设置

    locname = setlocale(LC_ALL, "");

    if (NULL == locname) {

           printf("setlocale() from environment failed.\n");

    }  else  {

           printf("setlocale() from environment succeed.\n");

    }

     print_current_loc();

    wprintf(L"Zhong text is: %ls\n", strzh);

    puts("End of program.");

    return 0;

}

// 打印当前 locale

void print_current_loc(){

    char* locname = setlocale(LC_ALL, NULL);

    printf("Current locale is: %s\n", locname);

}

要使上面程序成功编译并执行,需要注意一下几点:

Windows CRT 是不支持 UTF-8 编码作为 locale 的,运行时使用 setlocale(LC_ALL, ".65001") 会失败。使用 Linux 和 Cygwin 的 glibc 时,要在终端显示正确的中文,需满足以下条件:

不要混用 char 和 wchar_t 版本的流操作函数,否则会导致这些函数运行异常,我用Cygwin GCC 4测试混用 printf() 和 wprintf() 时,程序甚至崩掉,所以要将上面程序中 printf() 语句全注释掉才行。Window CRT 的实现则没有这个问题。

运行环境的 locale 设置要和程序中 setlocale() 设定的 locale 一致,比如:终端的活动字符集、环境变量(一般用 LANG),要设置为 *.UTF-8,才能显示 setlocale(LC_ALL, "zh_CN.UTF-8") 设定的 wchar_t 的中文字符。

用 GCC 编译时,要使用 UTF-8 编码保存源文件,这是 GCC 在编译时,将 wchar_t 文字量(以 L 打头)正确转换为 UCS 编码保存在对象文件中的必需条件,用 Native ANSI 编码(比如:GBK)有 wchar_t 文字量的源文件时,GCC 会编译出错,Linux 和 Cygwin 的 GCC 都有这个约束。另外在 Linux GCC 使用 UCS-4 编码保存 wchar_t,而 Windows 和 Cygwin GCC 使用 UCS-2。

用 wprintf() 时,要用 %ls 表示 wchar_t 的字符串,用 %s 表示 char 的字符串,具体参考:man 3 wprintf,而 Windows 的实现用 %ls、%s 都可以正确输出 wchar_t 字符串。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多