wchar_t vs wint_t

Der*_*unk 12 c string

这是一个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;
  }
Run Code Online (Sandbox Code Playgroud)

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

Bra*_*lor 18

wint_t能够存储任何有效值wchar_t.A wint_t也能够接受评估WEOF宏的结果(注意a wchar_t太窄而不能保持结果).

  • `wint_t`是`wchar_t`,`int`是`char`.我们不使用`int`的数组作为窄字符串,即使`getc()`返回`int`以便能够返回`EOF`.类似地,我们不使用`wint_t`的数组作为宽字符串,即使`getwc()`返回`wint_t`以便能够返回`WEOF`. (14认同)
  • @musiphil:你的评论应该是一个答案,它是唯一一个谈论它们之间的*概念*区别的人. (3认同)

Mes*_*ion 7

正如@musiphil在他的评论中所做的那样,我将尝试在这里进行扩展,并且和之间存在概念上的差异.wint_twchar_t

它们的不同大小是一个技术方面,它源于每个都具有非常不同的语义:

  • wchar_t如果您愿意,它足以存储字符代码点.因此,他们是未签名的.它们类似于char几乎在所有平台中,仅限于8位256值.因此,宽字符串变量自然是这种类型的数组或指针.

  • 现在输入字符串函数,其中一些函数需要能够返回任何 wchar_t加上其他状态.所以他们的返回类型必须大于wchar_t.所以wint_t使用,它可以表达任何宽的char也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’的值不同,并且不必为负数。” (3认同)
  • @chux:完成......我希望它现在有所改进,谢谢你的注意 (2认同)
  • `wchar_t`不一定足以存储代码点.值得注意的是,在Windows上它只有16位,这意味着需要使用代理对来表示基本多语言平面之外的代码点. (2认同)
  • UTF-16中的每个代理对由两个16位代码单元组成,而不是代码点.代码点不适合Windows上的wchar_t. (2认同)
  • 就术语而言,@rdb 是正确的(强调我的):[“来自其他平面(称为补充平面)的代码点被_编码为两个 16 位代码单元_称为代理对”](https://en.wikipedia. org/wiki/UTF-16#U.2B10000_to_U.2B10FFFF)。 (2认同)

lav*_*nio 1

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

\n\n

0x0000但由于 Unicode 值映射到从到 的所有值0xFFFF,因此没有剩余值可返回条件或错误代码。(有些人指出 Unicode 大于 16 位,这是事实;在这些情况下,使用代理项对。但这里的要点是 Unicode 使用所有可用值,没有为 EOF 留下任何值。)

\n\n

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

\n\n

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

\n\n

为什么我们不总是使用wcharthen 来代替 呢wint?大多数与字符串相关的函数都使用wchar,因为在大多数平台上它的 \xc2\xbd 的大小为wint,因此字符串具有较小的内存占用量。

\n

  • “_所有 Unicode 值都映射到 `0x0000` 到 `0xFFFF`_”……这是错误的。有效的 Unicode 值范围从“0”到“0x10FFFF”;请参阅&lt;http://unicode.org/glossary/#code_point&gt;。 (19认同)
  • 被否决是因为这个答案包含大量错误和误导性信息,并且无法以简单的方式解释“wint_t”类型。`wint_t` 只是为了容纳额外的 `WEOF` 值,以便 `getwc()` 和朋友可以指示失败情况。因此,“wint_t”可能比“wchar_t”更宽,但也可能相同。`wchar_t` 可能与 `char` 一样宽。另外,“EOF”是一些任意的负值。声明它为 -1 会导致代码不可移植。所有这些都是完全特定于实现的。通过谈论 Unicode 编码的工作原理,您完全错过了这个主题。 (11认同)
  • 您的答案大部分是正确的,但您提供了太多(依赖于平台的)详细信息。`wchar_t` 并不总是 16 位,我可以想到至少 2 个操作系统/编译器组合,其中它是 32 位。 (6认同)
  • @LoganCapaldo:实际上,Windows 是我所知道的唯一一个“wchar_t”是 16 位的平台。几乎*所有*其他平台都有 32 位“wchar_t”(但在一致的实现中,它可以是任何东西,低至 8 位)。 (5认同)
  • @MestreLion你的解释也有些错误。对于使用“wchar_t”(其值表示形式超过 21 位)的平台,它还可能允许超出 [U+0, U+10FFFF] 范围的无效 Unicode 代码点。仅由于名义上的原因,类型“wint_t”存储字符是错误的:它没有被设计为“正确”类型,因为“int”不被设计为通常存储字符。 (3认同)
  • UTF-8 字符的长度可以是 4 个字节,技术上甚至可以是 5 或 6 个字节,但这样的组合不是有效的 utf8 字符。 (2认同)
  • 令我惊讶的是,没有人指出这样一个事实:ISO/ANSI C *从不*强制在“wchar_t”上使用任何类型的 Unicode。如果有人想要 C 中的 Unicode,应该考虑 `char16_t`/`char32_t` (尽管没有很多有用的函数可用,例如没有 `getuc`)。 (2认同)
  • @TimČas 作为对您评论的补充,Android 的仿生使用 8 位“wchar_t”(它肯定根本无法支持“宽”字符形式的任何有用的 Unicode 编码)。 (2认同)