为啥 char 既不是有符号也不是无符号,而 wchar_t 是?

Posted

技术标签:

【中文标题】为啥 char 既不是有符号也不是无符号,而 wchar_t 是?【英文标题】:Why is char neither signed or unsigned, but wchar_t is?为什么 char 既不是有符号也不是无符号,而 wchar_t 是? 【发布时间】:2015-12-27 16:07:41 【问题描述】:

以下 C++ 程序编译没有错误:

void f(char)
void f(signed char)
void f(unsigned char)
int main()  

同一程序的wchar_t版本没有:

void f(wchar_t)
void f(signed wchar_t)
void f(unsigned wchar_t)
int main()

错误:重新定义“void f(wchar_t)” void f(signed wchar_t)

看来wchar_tunsigned。 为什么过载时会出现不一致?

【问题讨论】:

这在我看来不像合法的 C。是 C++ 吗? @ArlieStephens 是的,最好删除 C 标签。无需任何标头的 C++。 wchar_t 允许根据 [basic.fundamental] 签名或未签名。 @chris 我明白了。所以 wchar_t 是两者之一,而 char 两者都不是。 wchar_tchar 的不同之处在于char 可能是有符号类型或无符号类型,但仍是不等同于signed charunsigned char 的类型,与@ 不同987654332@ 可能是有符号或无符号类型,无法指定单独的 signed wchar_tunsigned wchar_t 类型。 【参考方案1】:

chars 都是不同的类型,可以重载

[basic.fundamental] / 1

[...] 普通 charsigned charunsigned char 是三种不同的类型, 统称为窄字符类型。 [...]

wchar_t也是一个distinct类型,但不能用signedunsigned限定,只能和标准整数类型一起使用。

[dcl.type] / 2

作为一般规则,最多允许一个 type-specifier 声明的完整 decl-specifier-seqtype-specifier-seqtrailing-type-specifier-seq。唯一的例外 这条规则如下:

[...]

signedunsigned 可以与 charlongshortint 组合使用。

[dcl.type.simple] / 2

[...] 表 9 总结了 simple-type-specifiers 及其指定类型的有效组合。

wchar_t 的签名由实现定义:

[basic.fundamental] / 5

[...] 类型 wchar_t 应具有相同的大小、符号和对齐方式 要求(3.11)作为其他整数类型之一,称为其 底层类型。

【讨论】:

我想知道为什么我的编译器让我摆脱“unsigned wchar_t”,如果它不是一个有效的限定符。我当然不能做像“unsigned bool”这样的事情...... @TrevorHickey 提交错误报告:)【参考方案2】:

char 是与signed charunsigned char 不同的类型。 wchar_t 是另一种不同的类型(用于类型标识目的),但它具有与其他整数类型完全相同的属性(大小、符号和对齐方式)。

来自 ISO 14882:2003, 3.9.1:

Plain charsigned charunsigned char 是三种不同的类型。

(...)

Type wchar_t 是一个 distinct 类型,其值可以表示 distinct 指定的最大扩展字符集的所有成员的代码 在受支持的语言环境(22.1.1)中。类型wchar_t 应具有相同的 尺寸、签名和对齐要求 (3.9) 作为其他要求之一 整数类型,称为其底层类型。

没有signed wchar_tunsigned wchar_t 这样的东西。文档中没有提到它。

【讨论】:

【参考方案3】:

char 是基本类型。 wchar_t 首先演变为库解决方案(在 C 中),然后成为内置类型具有底层类型,对应于之前用于 typedef 它的类型:

C++11 $3.9.1/5

类型wchar_t 应具有相同的 大小、符号和对齐要求 (3.11) 作为其他整数类型之一,称为其基础 输入。

这解释了为什么您不能更改 wchar_t 的签名,但它没有解释为什么存在未指定签名的 char 类型。


此外,大多数编译器默认选择带符号的char 是不切实际的,原因有几个。一个原因是负值很烦人,通常必须转换为无符号才能比较它们。另一个原因是 C 字符分类函数需要非负值(传递 EOF 时除外)。第三个原因是,在旧的幅度和符号或反码机器上,有一个不可用的值。

Stroustrup 的“C++ 的设计和演变”中可能对此有一些解释,但我对此表示怀疑。

这听起来像冻结的历史,对于当时的技术来说,这在某种程度上是有意义的。

【讨论】:

以上是关于为啥 char 既不是有符号也不是无符号,而 wchar_t 是?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 SQL Server 不支持无符号数据类型?

正确解释有符号与无符号

复制无符号字符数组

为啥在有符号和无符号表示之间转换一个数字?

为啥更喜欢二进制补码而不是有符号数的符号和大小?

无符号整数减法是不是定义了行为?