【问题标题】:printf output not affected by global locale?printf 输出不受全局语言环境的影响?
【发布时间】:2013-12-03 13:25:06
【问题描述】:

我无法让 Visual-C++ (VS 2005) 中的 printf 函数在我的整数中输出千位分隔符。

注意:评论表明这是printf 的正常行为。但是,C++ iostream 确实 将千位分隔符插入到数字中(使用 std::stringstreamimbue 进行了测试),所以这纯粹是 iostreams 的一个特性,并且不存在于“C”格式化函数中吗?

这是测试代码:

    setlocale(LC_ALL, ""); // -> User locale
    _locale_t loc = _create_locale(LC_ALL, ""); // -> user locale for *_l version

    struct lconv *pLocalSettings = localeconv();
    printf("Locale is: %s\n", setlocale(LC_NUMERIC, NULL));
    printf("Thousands separator set to : {%s}\n", pLocalSettings->thousands_sep);
    printf("Grouping set to: {%o}\n", int(pLocalSettings->grouping[0]));

    int i = 1000000;
    __int64 i64 = i * 2;
    printf("32 Bit integer output: %d\n", i);
    printf("64 Bit integer output: %I64d\n", i64);
    _printf_l("32 Bit integer output: %d\n", /*locale=*/loc, i);
    _printf_l("64 Bit integer output: %I64d\n", /*locale=*/loc, i64);
    _free_locale(loc);

输出是:

Locale is: German_Austria.1252
Thousands separator set to : {.}
Grouping set to: {3}
32 Bit integer output: 1000000
64 Bit integer output: 2000000
32 Bit integer output: 1000000
64 Bit integer output: 2000000

经过进一步检查,它似乎不是这样工作的。我试过这个:

#include <iostream>
#include <clocale>
using namespace std;

int main() {
    setlocale(LC_ALL, "en_US"); // -> User locale

    struct lconv *pLocalSettings = localeconv();
    printf("Locale is: %s\n", setlocale(LC_NUMERIC, NULL));
    printf("Thousands separator set to : {%s}\n", pLocalSettings->thousands_sep);
    printf("Grouping set to: {%o}\n", int(pLocalSettings->grouping[0]));

    int i = 1000000;
    long long  i64 = i * 2;
    printf("32 Bit integer output: %d\n", i);
    printf("64 Bit integer output: %I64d\n", i64);

    return 0;
}

http://www.compileonline.com/compile_cpp11_online.php 上(找不到永久链接。)

输出是:

Compiling the source code....
$g++ -std=c++11 main.cpp -o demo -lm -pthread -lgmpxx -lgmp -lreadline 2>&1

Executing the program....
$demo
Locale is: en_US
Thousands separator set to : {,}
Grouping set to: {3}
32 Bit integer output: 1000000
64 Bit integer output: 2000000

【问题讨论】:

  • 你确定 printf 应该这样做吗?
  • 我从来不知道 %d 在其输出中包含数千个分隔符...
  • @JoeZ - 那么做什么呢?
  • 这个问题没有得到满意的答案后你要写的自定义函数:)
  • LC_NUMERIC:确定数字格式的区域设置。此环境变量会影响使用 e、E、f、g 和 G 转换字符写入的数字的格式。

标签: c++ c visual-c++ internationalization locale


【解决方案1】:

让我分享一下我在这里学到的东西:

  • C locale 确实包含有关千位分隔符的信息,但此信息是 not used at allprintf* 系列函数组成的(除非您计算 flag extension ',无论如何 MSVC 中都不存在)
  • C++ locale 也包含信息,iostreams 实际上在格式化数字时使用它 (numpunct facet)
  • 使用 setlocale 设置全局 C 区域设置不会影响由 std::locale::global() 设置的全局 C++ 区域设置

  • 得到我的格式化数字的正确代码最终是:

    static std::locale user_locale("");
    std::wstringstream buf; 
    buf.imbue(user_locale); 
    buf << some_integer; 
    
  • 对于某些用例,可以通过using the facet directly 获得性能加速。

【讨论】:

  • 值得补充的是,std::locale::global(user_locale); 将适用于未来打开的所有流 - 即它们将自动成为 imbue-d。但是请注意,如果您将其用作main 中的第一行,则必须记住cout 已被打开,因此必须显式灌输cout
【解决方案2】:

我找到了IBM printf 文档,其中说语言环境会影响eEfgG 转换字符。

od 都不使用语言环境转换...

【讨论】:

  • 需要注意的是,浮点转换使用的语言环境用于小数点分隔符。 C-Standard printf 根本不使用千位分组分隔符。但是,存在一个扩展,其中' 字符可以包含在标志中,以根据当前语言环境进行分组。 (见herehere。)
【解决方案3】:

在他的书“标准 C 库”的第 90-93 页上,P.J. Plauger 展示了名为 _Fmtval() 的函数的代码,该函数使用 localeconv() 提供的信息格式化浮点值。调用者指定该值是否应格式化为具有指定小数位数的国际货币、本地货币、整数或浮点数。部分代码处理数字分组和分隔符的插入。这可以用作编写自己的函数的指南。

同一作者在以下链接中的文章提供了与本书类似的讨论,并提供了几乎相同版本的 _Fmtval()。不幸的是,文章提供的代码似乎包含一些 OCR 错误。如果可能,请参阅本书。

标准 C:格式化货币价值,P.J. Plauger

http://www.drdobbs.com/standard-c/184402377?pgno=4

【讨论】:

    【解决方案4】:

    有可能 OP 将 C 中的 printf 与 BASH 的 printf 混合在一起(它确实具有一些语言环境功能)??

    (我在 CrunchBang 11 “Waldorf”,源自 Debian 7 “Wheezy”)

    LANG=zh_CN.UTF-8
    LC_NUMERIC 未设置

    例如:

    $ printf "%d\n" 12345678
    12345678
    $ printf "%'d\n" 12345678
    12,345,678
    

    BASH printf command
    (参见字段和打印修饰符)

    【讨论】:

    猜你喜欢
    • 2015-12-09
    • 1970-01-01
    • 2018-01-21
    • 2021-09-29
    • 1970-01-01
    • 2017-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多