代码之家  ›  专栏  ›  技术社区  ›  S.S. Anne

为什么在使用wprintf时(版权符号)被替换为(C)?

  •  3
  • S.S. Anne  · 技术社区  · 4 年前

    当我试图打印版权符号时 © 具有 printf write ,它工作得很好:

    #include <stdio.h>
    
    int main(void)
    {
        printf("©\n");
    }
    

    #include <unistd.h>
    
    int main(void)
    {
        write(1, "©\n", 3);
    }
    

    输出:

    ©
    

    但当我试图用 wprintf ,我明白了 (C) :

    #include <stdio.h>
    #include <wchar.h>
    
    int main(void)
    {
        wprintf(L"©\n");
    }
    

    输出:

    (C)
    

    当我向添加呼叫时,它已修复 setlocale 然而:

    #include <stdio.h>
    #include <wchar.h>
    #include <locale.h>
    
    int main(void)
    {
        setlocale(LC_ALL, "");
        wprintf(L"©\n");
    }
    

    输出:

    为什么原始行为存在,为什么我打电话时它是固定的 setlocale ?此外,这种转换发生在哪里?之后我该怎么做 setlocale 违约?

    编译命令:

    gcc test.c
    

    locale :

    LANG=en_US.UTF-8
    LANGUAGE=
    LC_CTYPE="en_US.UTF-8"
    LC_NUMERIC="en_US.UTF-8"
    LC_TIME="en_US.UTF-8"
    LC_COLLATE="en_US.UTF-8"
    LC_MONETARY="en_US.UTF-8"
    LC_MESSAGES="en_US.UTF-8"
    LC_PAPER="en_US.UTF-8"
    LC_NAME="en_US.UTF-8"
    LC_ADDRESS="en_US.UTF-8"
    LC_TELEPHONE="en_US.UTF-8"
    LC_MEASUREMENT="en_US.UTF-8"
    LC_IDENTIFICATION="en_US.UTF-8"
    LC_ALL=
    

    echo $LC_CTYPE :

    
    

    uname -a :

    Linux penguin 4.19.79-07511-ge32b3719f26b #1 SMP PREEMPT Mon Nov 18 17:41:41 PST 2019 x86_64 GNU/Linux
    

    file test.c (所有示例均相同):

    test.c: C source, UTF-8 Unicode text
    

    gcc --version :

    gcc (Debian 6.3.0-18+deb9u1) 6.3.0 20170516
    Copyright (C) 2016 Free Software Foundation, Inc.
    This is free software; see the source for copying conditions.  There is NO
    warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    

    /lib/x86_64-linux-gnu/libc-2.24.so ( glibc 版本):

    GNU C Library (Debian GLIBC 2.24-11+deb9u4) stable release version 2.24, by Roland McGrath et al.
    Copyright (C) 2016 Free Software Foundation, Inc.
    This is free software; see the source for copying conditions.
    There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
    PARTICULAR PURPOSE.
    Compiled by GNU CC version 6.3.0 20170516.
    Available extensions:
            crypt add-on version 2.1 by Michael Glad and others
            GNU Libidn by Simon Josefsson
            Native POSIX Threads Library by Ulrich Drepper et al
            BIND-8.2.3-T5B
    libc ABIs: UNIQUE IFUNC
    For bug reporting instructions, please see:
    <http://www.debian.org/Bugs/>.
    

    cat /etc/debian_version :

    9.12
    
    0 回复  |  直到 4 年前
        1
  •  5
  •   dbush    4 年前

    新进程不会自动继承调用进程的区域设置。

    当程序首次启动时,它位于C语言环境中。这个 man page for setlocale(3) 如下所述:

    启动主程序时,选择可移植的“C”语言环境 默认情况下。通过调用以下命令,程序可以移植到所有地区:

    setlocale(LC_ALL, "");
    

    ...

    区域设置“C”或“POSIX”是一个可移植的区域设置;其LC_CTYPE部分对应于7位ASCII字符集。

    因此,如输出所示,任何多字节/非ASCII字符都会转换为一个或多个ASCII字符。

    可以按如下方式设置区域设置:

    setlocale(LC_ALL,“”);
    

    这个 LC_ALL flag指定更改所有与区域设置相关的变量。区域设置的空字符串表示根据相关环境变量设置区域设置。完成此操作后,您应该看到shell区域设置的字符。

    #include <stdio.h>
    #include <wchar.h>
    #include <locale.h>
    
    int main()
    {
        char *before = setlocale(LC_ALL, NULL);
        setlocale(LC_ALL, "");
        char *after = setlocale(LC_ALL, NULL);
    
        wprintf(L"before locale: %s\n", before);
        wprintf(L"after locale: %s\n", after);
        wprintf(L"©\n");
        wprintf(L"\u00A9\n");
        return 0;
    }
    

    输出:

    before locale: C
    after locale: en_US.utf8
    ©
    ©