【问题标题】:Is wint_t always at least as large as wchar_t? And how can unsigned short satisfy reqirements of wint_t?wint_t 是否总是至少和 wchar_t 一样大? unsigned short 如何满足 wint_t 的要求?
【发布时间】:2020-07-11 10:26:57
【问题描述】:

似乎每个人都认为wint_t 至少和wchar_t 一样大。但是 C 标准允许 wchar_t 范围的值不直接对应于扩展字符集中的任何字符:

WCHAR_MINWCHAR_MAX 不一定对应于扩展字符集的成员。

和:

wchar_t ,它是一个整数类型,其值范围可以表示支持的语言环境中指定的最大扩展字符集的所有成员的不同代码;空字符的代码值为零。

并且wint_t 必须能够仅保存扩展字符集成员的值和至少一个WEOF 的附加值:

wint_t ,它是一个默认不变的整数类型,参数promotions可以保存任何对应于扩展字符集成员的值,以及至少一个不对应于任何扩展字符集成员的值(见下文WEOF);

wint_t 在默认参数提升下保持不变的要求也不意味着 wint_t 大于 wchar_t,因为 wchar_t 也可能大到足以在默认参数提升下保持不变。

因此,在一些虚构的实现中,wchar_t 可能被定义得足够大,以容纳许多不在扩展字符集中的不必要值,并绕过默认参数提升。然后,此实现可以选择不在wint_t 中包含这些值。这允许wchar_t 大于wint_t

根据wchar_t 的标准大小必须至少为 1 字节,wint_t 至少为 2 字节。 (假设 8 位字节)

同样在 Microsoft Visual Studio 中 wint_ttypedefunsigned short。这如何满足默认参数促销保持不变的要求?我认为 C 允许使用 2 字节 wint_t,因为 int 在某些实现中可能是 2 字节。

【问题讨论】:

  • 这个note 似乎相关。
  • @KamilCuk,wchar_t 和 wint_t 可能是相同的整数类型,但这并不意味着它们必须是。尽管在通常使用 UTF 编码的实现中它们是。我关心的是 c 通常特别不寻常的实现。
  • gnu.org/software/libc/manual/html_node/Extended-Char-Intro.htmlin the GNU C Library wchar_t is always 32 bits wide
  • gcc 使用 UTF-32 所以 wchar_t 是 4 个字节。
  • 在 GNU C 库中,wchar_ttypedef intwint_ttypedef unsigned int

标签: c language-lawyer eof wchar-t


【解决方案1】:

wint_twchar_tintchar 相同,因此 sizeof(wchar_t) == sizeof(wint_t) 完全合法的实现,就像 implementations where sizeof(int) == sizeof(char) are allowed。事实上,对于char 情况,情况更糟,因为您不能为getcfgetc... 返回不同的类型,而对于wint_t,您可以在必要时将其简单地定义为更广泛的类型。您还可以看到标准甚至明确允许它

脚注 327) wchar_twint_t 可以是相同的整数类型。

http://www.iso-9899.info/n1570.html#7.29.1

标准还规定“值 WCHAR_MIN 和 WCHAR_MAX 不一定对应于扩展字符集的成员”,这并没有错。扩展字符集范围可以小于wchar_t 范围,因为char 中也会发生同样的情况。例如,如果基本字符集是 ASCII,那么它只使用可用范围的一半(或者如果CHAR_BIT > 8 则更少)。 wint_t

...默认情况下不变的整数类型参数提升,可以保存对应于扩展字符集成员的任何值,以及至少一个不对应于扩展字符集任何成员的值(参见 WEOF下面);

http://www.iso-9899.info/n1570.html#6.3.1.3

因此,如果扩展字符集比wchar_t 集小得多,那么它的大小可能甚至比wchar_t 还要小。由于0xFFFF is guaranteed not to be a Unicode character at all,将其用于WEOF 是完全有效的,尽管恕我直言有点奇怪,我不知道为什么MS 这样做

如果sizeof(wchar_t) == sizeof(wint_t)sizeof(int) == sizeof(char) 也有charwchar_t 可以表示的值,但intwint_t 不能在char/wchar_t 未签名的情况下表示。在这种情况下,它们之间的转换是实现定义的。如果您正在处理文本文件,那将不会有任何问题,尽管如果您正在读取二进制文件会导致问题。无论如何,在这种情况下,为了可移植性,您需要自己显式测试 EOF 和错误

int c;
while((c = /* fgetwc(in) */ fgetc(in)) != EOF || (!feof(in) && !ferror(in)))
    fputc(c, out);

这和what TI suggested一样

sizeof(char)==sizeof(int)(C2700、C2800、C5400、C5500)的目标上,您仍然不能可靠地使用 getc() 的返回值来检查文件结尾,因为 0xffff 会被误认为是文件的结尾。请改用feof()

CMUFIO34-C. Distinguish between characters read from a file and EOF or WEOF也这么说

因为EOF 是负数,它不应该匹配任何无符号字符值。然而,这仅适用于implementations,其中int 类型比char 宽。在intchar 具有相同宽度的实现上,字符读取函数可以读取并返回与EOF 具有相同位模式的有效字符。例如,如果攻击者将一个看起来像 EOF 的值插入到文件或数据流中以改变程序的行为,就会发生这种情况。

C 标准仅要求 int 类型能够表示 +32767 的最大值,并且 char 类型不大于 int。虽然不常见,但这种情况会导致整数常量表达式 EOF 与有效字符无法区分;即(int)(unsigned char)65535 == -1。因此,未能使用feof()ferror() 来检测文件结束和文件错误可能会导致在sizeof(int) == sizeof(char) 的罕见实现中错误地识别EOF 字符。

这个问题在阅读宽字符时更为常见。 fgetwc()、getwc()getwchar() 函数返回 wint_t 类型的值。该值可以表示下一个读取的宽字符,也可以表示WEOF,表示宽字符流的文件结束。在大多数实现中,wchar_t 类型与wint_t 具有相同的宽度,并且这些函数可以返回一个与WEOF 无法区分的字符。

在 UTF-16 字符集中,保证 0xFFFF 不是字符,这使得 WEOF 可以表示为值 -1。同样,当被视为带符号的 32 位整数时,所有 UTF-32 字符都是正数。所有广泛使用的字符集都设计有至少一个不代表字符的值。因此,如果使用宽字符或与int 一样宽的普通字符出现此问题,则需要在不考虑 C 编程语言的情况下设计自定义字符集。

另见

【讨论】:

    猜你喜欢
    • 2010-11-08
    • 2017-04-07
    • 2011-01-24
    • 2017-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-27
    相关资源
    最近更新 更多