gpt4 book ai didi

c - 为什么没有“unsigned wchar_t”和“signed wchar_t”类型?

转载 作者:行者123 更新时间:2023-12-04 23:40:00 35 4
gpt4 key购买 nike

字符的签名不规范。因此,有signed charunsigned char类型。因此,使用单个字符的函数必须使用既可以包含有符号字符又可以包含无符号字符的参数类型(此
类型选择为int),因为如果参数类型为char,我们将
在这样的代码中从编译器(如果使用-Wconversion)获取类型转换警告:

char c = 'ÿ';
if (islower((unsigned char) c)) ...

warning: conversion to ‘char’ from ‘unsigned char’ may change the sign of the result


(这里我们考虑如果islower()的参数类型为char会发生什么情况)

使它无需显式类型转换即可工作的是自动升级
charint

此外,引入 wchar_t的ISO C90标准没有说明任何内容
具体关于 wchar_t的表示。

来自glibc参考的一些引用:


wchar_t定义为 char是合法的





如果将 wchar_t定义为 char,则由于参数升级,必须将类型 wint_t定义为 int


因此, wchar_t可以很好地定义为 char,这意味着类似的规则
对于宽字符类型必须适用,即在某些情况下
wchar_t是肯定的,并且在某些实现中 wchar_t是负面的。
由此可见,必须存在 unsigned wchar_tsigned wchar_t类型(出于与 unsigned charsigned char类型相同的原因)。

私人通信表明,允许实现支持广泛
仅具有> = 0值的字符(与 wchar_t的符号无关)。有人知道这意味着什么吗?薄是否表示 wchar_t为16位
类型(例如),我们只能使用15位来存储宽字符的值吗?
换句话说,以符号扩展的 wchar_t是有效值吗?
另请参见 this question

此外,私人通讯显示该标准要求 wchar_t的任何有效值必须
wint_t表示。是真的吗

考虑以下示例:

#include <locale.h>
#include <ctype.h>
int main (void)
{
setlocale(LC_CTYPE, "fr_FR.ISO-8859-1");

/* 11111111 */
char c = 'ÿ';

if (islower(c)) return 0;
return 1;
}


为了使其可移植,我们需要将其强制转换为'(unsigned char)'。
这是必需的,因为 char可能是等效的 signed char
在这种情况下,设置最高位的字节将是符号
转换为 int时扩展,产生超出范围的值
unsigned char的范围。

现在,为什么这种情况与以下示例不同?
宽字符?

#include <locale.h>
#include <wchar.h>
#include <wctype.h>
int main(void)
{
setlocale(LC_CTYPE, "");
wchar_t wc = L'ÿ';

if (iswlower(wc)) return 0;
return 1;
}


我们需要在这里使用 iswlower((unsigned wchar_t)wc)
没有 unsigned wchar_t类型。

为什么没有 unsigned wchar_tsigned wchar_t类型?

更新

标准是否保证在以下两个程序中强制转换为 unsigned intint是正确的?
(我只是将 wint_twchar_t替换为它们在glibc中的实际含义)

#include <locale.h>
#include <wchar.h>
int main(void)
{
setlocale(LC_CTYPE, "en_US.UTF-8");
unsigned int wc;
wc = getwchar();
putwchar((int) wc);
}


-

#include <locale.h>
#include <wchar.h>
#include <wctype.h>
int main(void)
{
setlocale(LC_CTYPE, "en_US.UTF-8");
int wc;
wc = L'ÿ';
if (iswlower((unsigned int) wc)) return 0;
return 1;
}

最佳答案

TL; DR:

为什么没有未签名的wchar_t和已签名的wchar_t类型?

因为C的宽字符处理工具被定义为不需要它们。

更详细地说,

字符的签名不规范。

准确地说,“实现应将char定义为与签名char或未签名char具有相同的范围,表示形式和行为。” (C2011,6.2.5 / 15)

因此,有signed charunsigned char类型。

“因此”表示因果关系,很难说清楚因果关系,但是当您要处理数字而不是字符时,当然signed charunsigned char更合适。

因此,使用单个字符的函数必须使用既可以包含有符号字符又可以包含无符号字符的参数类型。

一点都不。可以使用类型char轻松定义使用单个字符的标准库函数,而不管该类型是否已签名,因为库实现确实知道其签名。如果这是一个问题,那么它也将同样适用于字符串函数-char将毫无用处。
您的getchar()示例是非正确的。它返回int而不是字符类型,因为它需要能够返回与任何字符都不对应的错误指示符。此外,您提供的代码与随附的警告消息不对应:它包含从intunsigned char的转换,但是没有从charunsigned char的转换。
其他一些字符处理函数接受int参数或返回类型为int的值,都是为了与getchar()和其他stdio函数兼容,并且是出于历史原因。在过去的日子里,您实际上根本无法通过char -它总是会被提升为int,这就是函数将(并且必须)接受的。尽管语言不断发展,但后来人们无法更改参数类型。

此外,引入了wchar_t的ISO C90标准没有说任何有关wchar_t表示的特定内容。

C90不再具有实际意义,但毫无疑问,它说的内容与C2011(7.19 / 2)非常相似,后者将wchar_t描述为

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

您对glibc参考的引用是非权威性的,只有glibc可能除外。在任何情况下,它们似乎都是注释,而不是说明,不清楚您为什么提出它们。当然,至少第一个是正确的。参考该标准,如果给定实现所支持的语言环境中指定的最大扩展字符集的所有成员都可以放入char中,则该实现可以将wchar_t定义为char。这样的实现曾经比今天更加普遍。
您问几个问题:

私人通信表明,允许实现仅支持> = 0值的宽字符(与wchar_t的符号无关)。有人知道这意味着什么吗?

我认为这意味着与您进行交流的任何人都不知道他们在说什么,或者他们在说什么与C标准提出的要求有所不同。您会发现在实践中,仅使用非负字符代码定义了字符集,但这并不是C标准所施加的约束。

例如,当wchar_t是16位类型时,thin是否意味着我们只能使用15位来存储宽字符的值?

C标准没有说明或暗示。您可以将任何支持的字符的值存储在wchar_t中。特别是,如果实现支持包含超过32767个字符代码的字符集,则可以将其存储在wchar_t中。

换句话说,以符号扩展的wchar_t是有效值是真的吗?

C标准没有说明或暗示。它甚至没有说wchar_t是否为带符号类型(如果不是,则符号扩展对其没有意义)。如果它是带符号的类型,则不能保证符号扩展表示某个受支持字符集中的字符的值(该值原则上可以为负)是否会产生一个也表示该字符中的字符的值集,或任何其他受支持的字符集。将wchar_t值加1也是一样。

另外,私人通信表明该标准要求wchar_t的任何有效值都必须由wint_t表示。是真的吗

这取决于您所说的“有效”。该标准说wint_t

是一种默认情况下不变的整数类型,参数提升时可以保留与扩展字符集的成员相对应的任何值,以及至少一个与扩展字符集的任何成员不对应的值。

(C2011,7.29.1.2)
wchar_t必须能够在任何受支持的语言环境中保存与扩展字符集的成员相对应的任何值。 wint_t也必须能够保留所有这些值。但是,wchar_t可能能够表示与任何支持的字符集中的任何字符都不对应的值。这些值在类型可以表示它们的意义上是有效的。不需要wint_t能够表示这样的值。
例如,如果任何受支持的语言环境中最大的扩展字符集使用的字符代码最多但不超过32767,则实现可以自由地将wchar_t实现为无符号的16位整数,而将wint_t实现为有符号的16位整数。这样,由wchar_t表示的不对应于扩展字符的值就不能由wint_t表示(但是wint_t对于其所需值仍具有许多不与任何字符对应的候选)。
关于字符和宽字符分类功能,唯一的答案是差异仅源于不同的规格。 char分类函数被定义为使用与getchar()定义要返回的值相同的值--1或字符值(如果需要)转换为unsigned char。另一方面,宽字符分类函数接受wint_t类型的参数,该参数可以表示所有不变的宽字符的值,因此不需要进行转换。
您声称在这方面

我们需要在这里使用iswlower((unsigned wchar_t)wc),但是没有unsigned wchar_t类型。

不,也许。您无需将wchar_t参数转换为iswlower()的任何其他类型,尤其是,您无需将其转换为显式的无符号类型。宽字符分类功能在这方面与常规字符分类功能不相似,这是事后考虑的。至于unsigned wchar_t,C不需要存在这种类型,因此可移植代码不应使用它,但在某些实现中它可能存在。

关于问题附加的更新:

标准是否说明在以下两个程序中将unsigned int和int强制转换是正确的? (我只是将wint_t和wchar_t替换为它们在glibc中的实际含义)

该标准在一般情况下并没有说明符合标准的实现。但是,我假设您的意思是具体询问wchar_tintwint_tunsigned int的符合实现。
在这样的实现中,您的第一个程序存在缺陷,因为它没有考虑getwchar()返回WEOF的可能性。如果不将WEOF转换为wchar_t类型,则不能保证产生与任何宽字符相对应的值。因此,将这种转换结果传递给putwchar()不会表现出已定义的行为。此外,如果用与WEOF相同的值(不能用UINT_MAX表示)定义int,则将该值转换为int具有独立于putwchar()调用的实现定义的行为。
另一方面,我认为您遇到的关键问题是,如果在第一个程序中getwchar()返回的值不是WEOF,那么通过转换为wchar_t可以保证它不变。 。在这种情况下,您的第一个程序将按预期执行,但不必强制转换为int(或wchar_t)。
同样,第二个程序是正确的,条件是宽字符文字对应于适用的扩展字符集中的一个字符,但是强制转换是不必要的,并且不进行任何更改。保证此类文字的wchar_t值可以由wint_t类型表示,因此强制转换会更改其操作数的类型,但不能更改该值。 (但是,如果文字与扩展字符集中的字符不对应,则行为是实现定义的。)
第三,如果您的目标是编写严格符合要求的代码,那么正确的做法以及这些特殊的宽字符函数的预期使用方式将是:

#include <locale.h>
#include <wchar.h>
int main(void)
{
setlocale(LC_CTYPE, "en_US.UTF-8");
wint_t wc = getwchar();
if (wc != WEOF) {
// No cast is necessary or desirable
putwchar(wc);
}
}

还有这个:
#include <locale.h>
#include <wchar.h>
#include <wctype.h>
int main(void)
{
setlocale(LC_CTYPE, "en_US.UTF-8");
wchar_t wc = L'ÿ';
// No cast is necessary or desirable
if (iswlower(wc)) return 0;
return 1;
}

关于c - 为什么没有“unsigned wchar_t”和“signed wchar_t”类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40755634/

35 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com