如何使用 gnome 终端从 c 控制台应用程序打印欧元符号

How to print euro sign from c console app using gnome terminal

提问人:clearcom0 提问时间:11/28/2022 更新时间:11/29/2022 访问量:88

问:

我正在尝试通过 c 控制台应用程序在 Gnome Terminal 应用程序的控制台上打印欧元符号。我的代码是:

#include <stdio.h>
#include <wctype.h>
#include <wchar.h>
#include <locale.h>

int main (int argc, char* argv[]) {
    setlocale(LC_CTYPE,"UTF-8");
    wchar_t w_char1 = '€';
    wprintf(L"%x\n", w_char1);
    wprintf(L"%c\n", w_char1);
    wchar_t w_char2=0xE282AC;
    wprintf(L"%x\n", w_char2);
    wprintf(L"%c\n", w_char2);
    wchar_t w_char3='\u20AC';
    wprintf(L"%x\n", w_char3);
    wprintf(L"%c\n", w_char3);
}

这将在控制台上打印以下内容:

e282ac

e282ac

e282ac

我已经尝试了使用和不使用 setlocale 的方法。在 Gnome 终端首选项的“兼容性”下,“编码”设置为 。Unicode -- UTF-8

知道为什么欧元符号不打印吗?

c utf-8 gnome-terminal 欧元

评论

1赞 tripleee 11/28/2022
UTF-8 编码已经是一个字节序列,而不是有效的字符代码。如果要保留此表示,只需 .实际的 Unicode 码位是 0x20AC。printf("%c%c%c\n", 0xE2, 0x82, 0xAC);
0赞 tripleee 11/28/2022
也许另见 utf8everywhere.org
0赞 Giacomo Catenazzi 11/28/2022
不要使用 wprint 和 w_char。这是一个添加更多字符的旧尝试。但后来 UTF-8 被开发出来,以避免所有w_char问题(双 API、需要重写所有软件等)。[注意:Microsoft 更改得太早,因此它有许多类似的 API 取决于字符的大小,JavaScript 也有类似的问题,但因为 UFT-16 可能需要 1 或 2 个单元(16 位)]。现代世界不应该担心这样的实施细节。随处使用(和 UTF-8)char
0赞 n. m. could be an AI 11/28/2022
“UTF-8”是系统上的有效区域设置名称吗?这是相当不寻常的。运行以查看有效的区域设置名称。locale -a

答:

1赞 Jonathan Leffler 11/28/2022 #1

这没有一个完整的解决方案,但我认为它提供了一些有用的解决方案指针。现在是午夜,我需要上床睡觉。

wprintf() 的 POSIX 手册页指示您需要在转换说明符之前使用修饰符:lc

l(埃尔)
指定后面的 、 、 、 或 转换说明符应用于 或 参数;以下转换说明符适用于指向参数的指针;以下转换说明符适用于参数;以下转换说明符适用于指向参数的指针;或对后面的 、 、 、 、 或 转换说明符没有影响。
diouxXlongunsigned longnlongcwint_tswchar_taAeEfFgG

然后是一个问题,即 a 是否转换为 a——它可能确实如此。wchar_twint_t

我遇到了一个问题,我必须编译该问题以抑制错误,例如:-Wno-multichar

$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes -fno-common wprintf37.c -o wprintf37
wprintf37.c: In function ‘main’:
wprintf37.c:9:23: error: multi-character character constant [-Werror=multichar]
    9 |     wchar_t w_char1 = '€';
      |                       ^~~
wprintf37.c:15:21: error: multi-character character constant [-Werror=multichar]
   15 |     wchar_t w_char3='\u20AC';
      |                     ^~~~~~~~
cc1: all warnings being treated as errors
$

您还应该检查该操作是否有效——它不适合我。我使用并检查了它;这奏效了。我正在使用 Mac,并且已在环境中设置。我仍然没有看到欧元符号。setlocale()setlocale(LC_ALL, "")LANG=en_us.UTF-8

嗯......

当事情失败时,调试的规则之一是“检查每个可以报告错误的函数”。此代码执行此操作,结果如下所示:

#include <errno.h>
#include <locale.h>
#include <stdio.h>
#include <string.h>
#include <wchar.h>
#include <wctype.h>

static void err_warn(int rv, const char *msg)
{
    fwprintf(stderr, L"%s: rv = %d (%d) %s\n", msg, rv, errno, strerror(errno));
    errno = 0;
    clearerr(stdout);
}

int main(void)
{
    if (setlocale(LC_ALL, "") == NULL)
    {
        fprintf(stderr, "failed to set the default locale\n");
        return 1;
    }
    int rv;
    wchar_t w_char1 = '€';
    if ((rv = wprintf(L"%x\n", w_char1)) < 0)
        err_warn(rv, "wprintf - 1");
    if ((rv = wprintf(L"C1 = %lc\n", w_char1)) < 0)
        err_warn(rv, "wprintf - 2");
    putwchar(L'\n');
    fflush(stdout);

    wchar_t w_char2=0xE282AC;
    if ((rv = wprintf(L"%x\n", w_char2)) < 0)
        err_warn(rv, "wprintf - 3");
    if ((rv = wprintf(L"C2 = %lc\n", w_char2)) < 0)
        err_warn(rv, "wprintf - 4");
    putwchar(L'\n');
    fflush(stdout);

    wchar_t w_char3='\u20AC';
    if ((rv = wprintf(L"%x\n", w_char3)) < 0)
        err_warn(rv, "wprintf - 5");
    if ((rv = wprintf(L"C3 = %lc\n", w_char3)) < 0)
        err_warn(rv, "wprintf - 6");
    putwchar(L'\n');
    fflush(stdout);

    char s[] = "€";
    if ((rv = wprintf(L"S = %s\n", s)) < 0)
        err_warn(rv, "wprintf - 7");

    return 0;
}

输出(在我的 Mac 上):

e282ac
wprintf - 2: rv = -1 (92) Illegal byte sequence
C1 = 
e282ac
wprintf - 4: rv = -1 (92) Illegal byte sequence
C2 = 
e282ac
wprintf - 6: rv = -1 (92) Illegal byte sequence
C3 = 
S = €

请注意,错误报告函数会清除标准输出 () 上的错误状态并重置为零 — 没有标准 C 库函数这样做。在我打电话之前,所有操作都报告了第一次失败。clearerr(stdout)errnoclearerr()

我认为可能有必要使用或类似的东西。查看 §6.4.4.4 字符常量§6.4.5 字符串文字以获取更多想法。u8'€'


二十四小时后。

此代码运行良好:

#include <errno.h>
#include <locale.h>
#include <stdio.h>
#include <string.h>
#include <wchar.h>
#include <wctype.h>

static void err_warn(int rv, const char *msg)
{
    fwprintf(stderr, L"%s: rv = %d (%d) %s\n", msg, rv, errno, strerror(errno));
    errno = 0;
    clearerr(stdout);
}

int main(void)
{
    if (setlocale(LC_ALL, "") == NULL)
    {
        fprintf(stderr, "failed to set the default locale\n");
        return 1;
    }
    int rv;

    /* This now works */
    wchar_t w_char1 = L'€';
    if ((rv = wprintf(L"%x\n", w_char1)) < 0)
        err_warn(rv, "wprintf - 1");
    if ((rv = wprintf(L"C1 = %lc\n", w_char1)) < 0)
        err_warn(rv, "wprintf - 2");
    putwchar(L'\n');
    fflush(stdout);

    /* Still failing */
    wchar_t w_char2 = 0xE282AC;
    if ((rv = wprintf(L"%x\n", w_char2)) < 0)
        err_warn(rv, "wprintf - 3");
    if ((rv = wprintf(L"C2 = %lc\n", w_char2)) < 0)
        err_warn(rv, "wprintf - 4");
    putwchar(L'\n');
    fflush(stdout);

    /* This works */
    wchar_t w_char3 = 0x20AC;
    if ((rv = wprintf(L"%x\n", w_char3)) < 0)
        err_warn(rv, "wprintf - 5");
    if ((rv = wprintf(L"C2 = %lc\n", w_char3)) < 0)
        err_warn(rv, "wprintf - 6");
    putwchar(L'\n');
    fflush(stdout);

    /* This now works */
    wchar_t w_char4 = L'\u20AC';
    if ((rv = wprintf(L"%x\n", w_char4)) < 0)
        err_warn(rv, "wprintf - 7");
    if ((rv = wprintf(L"C3 = %lc\n", w_char4)) < 0)
        err_warn(rv, "wprintf - 8");
    putwchar(L'\n');
    fflush(stdout);

    char s[] = "€";
    if ((rv = wprintf(L"S = %s\n", s)) < 0)
        err_warn(rv, "wprintf - 9");

    return 0;
}

它给出的输出是:

20ac
C1 = €

e282ac
wprintf - 4: rv = -1 (92) Illegal byte sequence
C2 = 
20ac
C2 = €

20ac
C3 = €

S = €

请注意,成功的值都包含 U+20AC。