首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >多次调用setlocale

多次调用setlocale
EN

Stack Overflow用户
提问于 2020-12-06 10:01:38
回答 1查看 247关注 0票数 4

我试图弄清楚C++是如何支持Unicode的。

当我想输出多语言文本到控制台时,我调用std::setlocale。但是,我注意到结果取决于先前对setlocale的调用。

考虑下面的例子。如果运行时不带参数,它只调用setlocale一次,否则它会先调用setlocale来获取当前区域设置的值,然后在函数的末尾还原它。

代码语言:javascript
复制
#include <iostream>
#include <locale>

using namespace std;

int main(int argc, char** argv)
{
    char *current_locale = 0;

    if (argc > 1) {
        current_locale = setlocale(LC_ALL, NULL);   
            wcout << L"Current output locale: " << current_locale << endl;
    }

    char* new_locale = setlocale(LC_ALL, "ru_RU.UTF8");
    if (! new_locale)
        wcout << L"failed to set new locale" << endl;
    else
        wcout << L"new locale: " << new_locale << endl;


    wcout << L"Привет!" << endl;

    if (current_locale) setlocale(LC_ALL, current_locale);
    return 0;
}

产出是不同的:

代码语言:javascript
复制
:~> ./check_locale 
new locale: ru_RU.UTF8
Привет!
:~> ./check_locale 1
Current output locale: C
new locale: ru_RU.UTF8
??????!

在未来的setlocale(LC_ALL, NULL)调用中,是否有什么需要处理的setlocale

编译器是g++ 7.5.0clang++ 7.0.1。控制台是图形终端中的linux控制台。

关于系统配置的更多详细信息: OpenSUSE 15.1、Linux4.12、glibc 2.26、libstdc++6-10.2.1

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-12-06 10:54:27

在未来的setlocale调用中是否需要处理setlocale(LC_ALL,NULL)?

不,setlocale(..., NULL)不修改当前区域设置。以下代码很好:

代码语言:javascript
复制
setlocale(LC_ALL, NULL);
setlocale(LC_ALL, "ru_RU.UTF8");
wprintf(L"Привет!\n");

但是,以下代码将失败:

代码语言:javascript
复制
wprintf(L"anything"); // or even just `fwide(stdout, 1);`
setlocale(LC_ALL, "ru_RU.UTF8");
wprintf(L"Привет!\n");

问题是,流有自己的区域设置,在流方向被更改为wide的点上确定。

代码语言:javascript
复制
// here stdout has no orientation and no locale associated with it
wprintf(L"anything");
   // `stdout` stream orientation switches to wide stream
   // current locale is used - `stdout` has C locale

setlocale(LC_ALL, "ru_RU.UTF8");
wprintf(L"Привет!\n");
   // `stdout` is wide oriented
   // current locale is ru_RU.UTF-8
   // __but__ the locale of `stdout` is still C and cannot be changed!

我找到的关于这个gnu.org流与I18N的唯一文档强调了我的:

由于流是在无定向状态下创建的,因此此时没有与其相关联的转换。将使用的转换由在流面向LC_CTYPE时选定的类别确定。如果在运行时更改了区域设置,这可能会产生令人惊讶的结果,除非有人注意。这只是另一个很好的理由,让我们尽快明确地定位这条溪流,或许可以通过呼叫fwide来实现。

您可以:

  • 对C++流和C FILE使用单独的区域设置(参见这里):

代码语言:javascript
复制
std::ios_base::sync_with_stdio(false);
std::wcout.imbue(std::locale("ru_RU.utf8"));
  • 重新打开stdout

代码语言:javascript
复制
wprintf(L""); // stdout has C locale
char* new_locale = setlocale(LC_ALL, "ru_RU.UTF8");
freopen("/dev/stdout", "w", stdout); // stdout has no stream orientation
wprintf(L"Привет!\n"); // stdout is wide and ru_RU locale 
  • 我认为(未经测试)在glibc中,您甚至可以使用显式区域设置重新打开stdout (参见GNU开放流):

代码语言:javascript
复制
freopen("/dev/stdout", "w,css=ru_RU.UTF-8", stdout);
std::wcout << L"Привет!\n"; // fine
  • 在任何情况下,尝试在做任何其他事情之前尽快设置区域设置。
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65166777

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档