【问题标题】:Why storing Unicode Characters in char works?为什么将 Unicode 字符存储在 char 中有效?
【发布时间】:2016-04-13 04:39:46
【问题描述】:

我编写了一个程序来从终端测试 I/O:

#include <stdio.h>
int main()
{
    char *input[100];
    scanf("%s", input);
    printf("%s", input);
    return 0;

}

它可以正常使用 ASCII 字符,但也可以使用 Unicode 字符和表情符号。

这是为什么?

【问题讨论】:

  • 我认为这条线 char* input [100] 你的意思是 char input [100]char *char **’ 是有区别的
  • @KaiIskratsch:这也取决于the normalization --- NFD、NFC 等。
  • @AndrewHenle:由于 UTF-8 的工作原理,您提出的是非法的 UTF-8。 0x00 总是 NUL(这适用于0x000x7F 范围内的所有内容——它与ASCII 相同)。多字节序列(无论是否开始)总是在&gt;= 0x80 范围内。这就是为什么许多古老的 C 程序可以将 UTF-8 视为任何其他编码,以及 C 字符串(以 0 结尾)仍然有效的原因!
  • @AndrewHenle:假设 OP 在一个 8 位 char 的系统上(这不是一个不合理的假设),这个问题强烈暗示 UTF-8 ---或诸如 UTF-EBCDIC 之类的变体(我怀疑是后者)。请记住,他确实说过 Unicode 字符有效。
  • @AndrewHenle:他提到了表情符号的工作; AFAIK,没有单字节编码(例如 ISO-8859-1)支持这一点。他还在评论中提到他使用 Linux,现在 Linux 使用 UTF-8。

标签: c unicode char


【解决方案1】:

您的代码可以正常工作,因为输入和输出流具有相同的编码,并且您无需对c 执行任何操作。

基本上,你输入一些东西,它被转换成一个字节序列,然后存储在c中,然后你将bytes的序列发回stdoutstdout将它们转换回可读的字符。

只要编码和解码过程兼容,就会得到“预期”的结果。

现在,如果您尝试使用标准的“字符串”C 函数会发生什么?假设您在终端中输入了“♠Hello”,您将获得预期的输出,但是:

strlen(c) -> 8
c[0] -> Some strange character
c[3] -> H

你看到了吗?您可以在char 数组中存储您想要的任何内容,但这并不意味着您应该这样做。如果要处理扩展字符集,请改用wchar_t

【讨论】:

  • 我的 0.02 美元:char 数组通常比wchar_t 数组更好。 char 在大多数相关系统中保证为 8 位(因此您至少可以始终在其中存储 UTF-8),但 wchar_t 因操作系统而异。此外,wchar_t 也不保证是 Unicode。最后,每个字符的访问非常、非常很少需要(即使在 UTF-32/32 位 wchar_t 中也无法直接进行!)。
  • @TimČ我不反对,我不是专家,但如果你使用char,你必须手动处理编码,而wchar_t 给你某种抽象。 wchar_t 可能因操作系统而异,但其行为似乎比 char 更明确(我在我的 Linux 和 Windows 上使用 wchar_t 具有相同的行为,而 char 在它们之间差异很大)。
  • @TimČ按字符还是按字素?从技术上讲,utf-32 可以做到前者……只是后者不行
  • @Mgetz:我认为 UTF-32 也做不到。它可以做代码点,但由于组合字符(不是真正的字符),单个代码点不一定是单个 linguistic 字符(这就是我的意思 - -- 也不是字素)。无论如何,这里的命名法有点混乱,而且模棱两可,所以区别是语义问题。
【解决方案2】:

您可能在 Linux 上运行,您的终端设置为 UTF-8,因此scanf 生成 UTF-8,printf 可以输出它。 UTF-8 的设计使得char[] 可以存储它。我明确使用char[] 而不是char,因为非ASCII 字符需要超过一个字节。

【讨论】:

  • 好吧,char[] 可以在任何系统中存储 UTF-8,因为它(间接地)保证至少为 8 位。不过,它可能会在某些系统中浪费位(例如,某些具有 32 位 char 的 DSP)。
  • 难道不是反过来吗? “..char[] 可以存储 UTF-8”似乎无关紧要,因为 all chars 可以存储 UTF-8。关键是显然在 OP 的系统上,“ASCII 字符,但 [..] 还有 [..] Unicode 字符和表情符号”被处理为 UTF8。
  • @Jongware:我认为更准确的说法是,在现代 Linux 中,char[] 预计将是 API 的 UTF-8。但它可以在任何系统中都是 UTF-8(事实上,越来越多的库正在做出这样的假设 --- 根据需要转换为 WinAPI 的 UTF-16)。
【解决方案3】:

您的程序未定义,因为它具有未定义的行为。

scanf("%s", input);

需要一个指向字符串的指针,但是

char *input[100];

input是指向charchar *的指针。

您的程序可能会工作,因为您传递给 scanf 的缓冲区有足够的大小来存储 unicode 字符,并且您传递的字符之间没有 NULL 字节,但它可能无法正常工作,因为 C 的实现在 UB 的情况下,您(和任何其他)机器上的任何操作都可以执行。

【讨论】:

  • 操作员说It works as it should with ASCII characters, but it also works with unicode characters and emoji. why is this?
  • 不重要,因为程序未定义
  • 他给出的例子是UB,而不是Question。
  • @tinky_winky 程序的结果,它的运行产生的所有影响都是未定义的,并不重要 这完全不相关,因为实际上input 缓冲区在该程序比预期大 4 或 8 倍 - 虽然技术上未定义,但它与问题无关
  • 我不是在和你争论,我只是想让这个问题相关,这当然与他给出的例子不同,但问题是:It works as it should with ASCII characters, but it also works with unicode characters and emoji. why is this?
猜你喜欢
  • 1970-01-01
  • 2023-02-10
  • 1970-01-01
  • 2018-07-15
  • 2018-05-02
  • 1970-01-01
  • 2018-09-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多