为什么char既不是有符号的也不是无符号的,但wchar_t却是有符号的?

9
下面这个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_t 是无符号的。
为什么在重载中存在不一致性?


1
这看起来不像是合法的 C 代码。它是 C++ 吗? - Arlie Stephens
1
根据[basic.fundamental],wchar_t可以是有符号的或无符号的。 - chris
1
@chris 我明白了。所以wchar_t是二者之一,而char则不是。 - Trevor Hickey
2
wchar_tchar 不同之处在于,char 可以是有符号类型或无符号类型,但仍然不等同于 signed charunsigned char 类型,而 wchar_t 可以是有符号或无符号类型,没有办法指定一个单独的 signed wchar_tunsigned wchar_t 类型。 - user539810
你的结论是不正确的。它告诉你 wchar_tsigned wchar_t 是相同的。有趣的是它对 char 没有做出同样的抱怨。 - Mark Ransom
显示剩余2条评论
3个回答

11

char是不同的类型,可以重载。

[basic.fundamental] / 1

[...] 原始charsigned charunsigned char是三种不同的类型,统称为“窄字符类型”。[...]

wchar_t也是一种不同的类型,但不能用signedunsigned修饰,只能用于标准整数类型。

[dcl.type] / 2

通常,在声明的完整decl-specifier-seqtype-specifier-seqtrailing-type-specifier-seq中仅允许最多一个type-specifier。以下情况是唯一的例外:

[...]

signedunsigned可与charlongshortint组合使用。

[dcl.type.simple] / 2

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

enter image description here

wchar_t的符号性是由实现定义的:

[basic.fundamental] / 5

[...] 类型应具有与另一个整数类型相同大小、符号性和对齐要求(3.11),称为它的底层类型。


我不知道为什么我的编译器会让我使用“unsigned wchar_t”,尽管它不是一个有效的限定符。如果我尝试使用“unsigned bool”这样的语句肯定是行不通的。 - Trevor Hickey
4
提交一个错误报告 :) - user657267

4

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

根据ISO 14882:2003,3.9.1:

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

(...)

类型wchar_t是一种独特的类型,其值可以表示所有支持语言环境中指定的最大扩展字符集的所有成员的不同编码(22.1.1)。类型wchar_t应该具有与另一种整数类型相同的大小、符号位和对齐要求(3.9),称为其基本类型。

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


4

char 是一种基本类型。 wchar_t 最初作为库解决方案(在 C 语言中),然后成为内置类型,具有底层类型,对应于先前用于 typedef 的类型。

C++11 $3.9.1/5

类型 wchar_t 必须具有与其他整数类型之一相同的大小、符号和对齐要求(3.11),称其为其底层类型。

这就解释了为什么无法更改 wchar_t 的符号性,但并没有解释为什么存在未指定符号性的 char 类型。


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

Stroustrup 的《C++ 设计与演化》可能有一些解释,但我怀疑它。听起来像是被“固化的历史”,在当时的技术中某个时刻有一定的意义。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接