Почему © (символ авторского права) заменяется на (C) при использовании wprintf?

Когда я пытаюсь напечатать символ авторского права © с помощью printf или write, все работает нормально:

#include <stdio.h>

int main(void)
{
    printf("©\n");
}

#include <unistd.h>

int main(void)
{
    write(1, "©\n", 3);
}

Output:

©

Но когда я пытаюсь напечатать его с помощью 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

person S.S. Anne    schedule 28.02.2020    source источник
comment
Один ideone.com/LMOH1T Два ideone.com/D6D17k   -  person n. 1.8e9-where's-my-share m.    schedule 28.02.2020
comment
Он переведен с помощью glibc, автоматически сгенерированного из glibc/C- транслит.ч.в.   -  person KamilCuk    schedule 29.02.2020


Ответы (1)


Локаль вызывающих процессов не наследуется автоматически новым процессом.

Когда программа запускается впервые, она находится в локали C. справочная страница для setlocale(3) говорит следующее:

При запуске основной программы по умолчанию выбирается переносимая локаль "C". Программу можно сделать переносимой на все языки, вызвав:

setlocale(LC_ALL, "");

...

Локаль "C" или "POSIX" является переносимой локалью; его часть LC_CTYPE соответствует 7-битному набору символов ASCII.

Таким образом, любой многобайтовый/не-ASCII-символ преобразуется в один или несколько символов ASCII, как показывает вывод.

Локаль можно установить следующим образом:

setlocale(LC_ALL, "");

Флаг LC_ALL указывает на изменение всех переменных, связанных с локалью. Пустая строка для локали означает установку локали в соответствии с соответствующими переменными среды. Как только это будет сделано, вы должны увидеть символы локали вашей оболочки.

#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
©
©
person dbush    schedule 28.02.2020