【问题标题】:wchar_t vs wint_twchar_t 与 wint_t
【发布时间】:2010-11-08 01:30:33
【问题描述】:

这是一个 ANSI C 问题。我有以下代码。

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

  int main()
  {
    if (!setlocale(LC_CTYPE, "")) {
      printf( "Can't set the specified locale! "
              "Check LANG, LC_CTYPE, LC_ALL.\n");
      return -1;
    }
    wint_t c;
    while((c=getwc(stdin))!=WEOF)
      {
    printf("%lc",c);
      }
    return 0;
  }

我需要完整的 UTF-8 支持,但即使在这个最简单的级别上,我能以某种方式改进它吗?为什么使用wint_t,而不是wchar,并进行适当的更改?

【问题讨论】:

    标签: c string


    【解决方案1】:

    wint_t 能够存储wchar_t 的任何有效值。 wint_t 也能够接受评估 WEOF 宏的结果(请注意,wchar_t 可能太窄而无法容纳结果)。

    【讨论】:

    • 好的,谢谢。所以,简而言之:那么什么时候使用 wchar_t 更好呢?为什么不总是使用 wint_t?
    • wint_twchar_tintchar。我们不会将int 的数组用于窄字符串,即使getc() 返回int 以便能够返回EOF。同样,我们不会将wint_t 的数组用于宽字符串,即使getwc() 返回wint_t 以便能够返回WEOF
    • @musiphil:你的评论应该是一个答案,它是唯一谈论它们之间概念差异的评论。
    【解决方案2】:

    正如@musiphil 在他的评论中所说的那样,我将在这里尝试扩展,wint_twchar_t 之间存在概念差异。

    它们的不同大小是一个技术方面,因为它们都有非常不同的语义

    • wchar_t 足够大,可以存储字符代码点(如果您愿意)。因此,它们是未签名的。它们类似于char,几乎在所有平台上都限制为 8 位 256 值。所以宽字符字符串变量自然就是这种类型的数组或指针。

    • 现在输入字符串functions,其中一些需要能够返回any wchar_t 以及额外的statuses。所以它们的返回类型必须大于wchar_t。所以使用wint_t,它可以表示任何宽字符,也可以表示WEOF。作为一种状态,它也可以是否定(通常是),因此wint_t 很可能是已签名。我说“可能”是因为 C 标准没有强制。但无论符号如何,状态值都需要wchar_t 的范围之外。它们仅作为返回值有用,绝不意味着存储这样的字符。

    与“经典”charint 的类比有助于消除任何混淆:字符串不是int [] 类型,而是char var[](或char *var)。并不是因为char“是int 大小的一半”,而是因为这就是字符串

    您的代码看起来正确:c 用于检查 getwch() 的结果,因此它是 wint_t。如果它的值不是WEOF,正如你的if 测试的那样,那么将它分配给wchar_t 字符(或字符串数​​组、指针等)是安全的

    【讨论】:

    • 嗯不同意:C11 规范说 wint_t 可以签名或未签名。此外,它还说“宏 WEOF 的值可能与 EOF 的值不同,并且不必为负数。”
    • wchar_t 不一定大到足以存储代码点。值得注意的是,在 Windows 上它只有 16 位,这意味着需要使用代理对来表示基本多语言平面之外的代码点。
    • @rdb:这有点超出了问题的范围,但我的理解是每个代理仍然是一个代码点,只是他们单独没有直接映射到一个字符。因此,即使在 Windows 上,概念上应该使用 wchar_t 来存储代码点,只是需要额外的工作来正确处理代理对。
    • UTF-16 中的每个代理对由两个 16 位代码单元组成,而不是代码点。代码点不适合 Windows 上的 wchar_t。
    【解决方案3】:

    UTF-8 是一种可能的 Unicode 编码。它定义每个字符 1、2、3 或 4 个字节。当您通过getwc() 阅读它时,它将获取一到四个字节并从中组成一个单一的Unicode 字符codepoint,该字符将适合wchar(可以是16 位甚至32 位宽,取决于平台)。

    但是由于 Unicode 值映射到从 0x00000xFFFF 的所有值,因此没有值可以返回条件或错误代码。(有人指出 Unicode 大于 16 位,即是的;在这些情况下使用surrogate pairs。但这里的重点是Unicode 使用所有 可用值,而没有为EOF 留下任何值。)

    各种错误代码包括 EOF (WEOF),它映射到 -1。如果您将getwc() 的返回值放在wchar 中,则无法将其与Unicode 0xFFFF 字符区分开来(顺便说一句,它无论如何都是保留的,但我离题了)。

    所以答案是使用更宽的类型,wint_t(或int),它至少包含 32 位。这给出了实际值的低 16 位,任何位设置在该范围之外的任何东西都意味着发生了除了字符返回之外的事情。

    为什么我们不总是使用wchar 而不是wint?大多数与字符串相关的函数都使用wchar,因为在大多数平台上它的大小是wint 的1/2,因此字符串占用的内存更小。

    【讨论】:

    • 您的答案大部分是正确的,但您提供了太多(平台相关的)细节。 wchar_t 总是 16 位,我可以想到至少 2 个操作系统/编译器组合,它是 32。
    • "所有 Unicode 值都映射到 0x00000xFFFF" ...这是错误的。有效的 Unicode 值范围从 00x10FFFF;见 unicode.org/glossary/#code_point>.
    • @LoganCapaldo:实际上,Windows 是我所知道的唯一一个wchar_t 是 16 位的平台。几乎所有其他平台都有 32 位 wchar_t(但在符合标准的实现中,它可以是任何东西,低至 8 位)。
    • 投反对票,因为此答案包含大量错误和误导性信息,并且未能以简单的方式解释 wint_t 类型。 wint_t 仅用于容纳附加的WEOF 值,以便getwc() 和朋友可以指示失败情况。因此,wint_t 可能wchar_t 宽,但也可能相同。 wchar_t 可能与 char 一样宽。此外,EOF 是一些任意的负值。声明它是 -1 会导致代码不可移植。所有这些都是完全特定于实现的。通过谈论 Unicode 编码是如何工作的,你完全错过了这个话题。
    • @MestreLion 您的解释也有些错误。对于使用 wchar_t(其值表示形式超过 21 位)的平台,它还可能允许 [U+0, U+10FFFF] 范围外的无效 Unicode 代码点。 wint_t 类型存储字符是错误的,只是因为名义上的原因:它不是设计为“正确”类型,因为 int 不是设计用于正常存储字符。
    猜你喜欢
    • 2017-04-07
    • 2017-03-28
    • 2020-07-11
    • 1970-01-01
    • 2011-07-29
    • 1970-01-01
    • 2021-06-27
    • 2020-12-02
    • 2019-11-27
    相关资源
    最近更新 更多