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

Posted

技术标签:

【中文标题】为啥在使用 wprintf 时 ©(版权符号)被替换为 (C)?【英文标题】:Why is © (the copyright symbol) replaced with (C) when using wprintf?为什么在使用 wprintf 时 ©(版权符号)被替换为 (C)? 【发布时间】:2020-06-12 23:27:31 【问题描述】:

当我尝试使用printfwrite 打印版权符号© 时,效果很好:

#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.soglibc版本):

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

【问题讨论】:

一个ideone.com/LMOH1T 两个ideone.com/D6D17k 它是由glibc从glibc/C-translit.h.in自动生成的。 【参考方案1】:

调用进程的语言环境不会被新进程自动继承。

当程序第一次启动时,它是在 C 语言环境中。 man page for setlocale(3) 表示以下内容:

在主程序启动时,选择可移植的“C”语言环境 默认。可以通过调用使程序可移植到所有语言环境:

setlocale(LC_ALL, "");

...

语言环境“C”或“POSIX”是可移植语言环境;其 LC_CTYPE 部分对应 7 位 ASCII 字符集。

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

语言环境可以设置如下:

setlocale(LC_ALL, "");

LC_ALL 标志指定更改所有与语言环境相关的变量。 locale 的空字符串表示根据相关的环境变量设置 locale。完成此操作后,您应该会看到 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
©
©

【讨论】:

以上是关于为啥在使用 wprintf 时 ©(版权符号)被替换为 (C)?的主要内容,如果未能解决你的问题,请参考以下文章

wprintf: %p 带 NULL 指针

字体不支持符号时如何在WPF文本框中插入版权、商标、服务标记等

使用 PHP 将注册商标符号/版权符号插入 MySQL

拼命尝试使用 wprintf 在 64 位 NASM x86 程序集中打印 unicode

为啥在构建SQL命令时使用地址符号@? [复制]

为啥在检查符号是不是存在时不能使用否定运算符?