默认情况下,char是有符号的还是无符号的?

204
在《C语言程序设计全面指南》一书中提到,char默认是无符号的。 但我正试着用GCC和Visual Studio验证这一点。结果默认情况下被视为有符号的。 那么哪一个是正确的呢?

8
我信任的一本C语言参考书是Harbison & Steele的《C参考手册》(http://www.careferencemanual.com/)。当然,标准是最终的准则,但它不太易读,并且只提供了关于标准之外(例如POSIX)的预先标准和常见用法的极少信息。Harbison&Steele手册非常易读、详细并且可能比大多数参考书更正确。但是它也不是教程,所以如果你处于学习的初步阶段,跳进这本书可能并不是一个好主意。 - Michael Burr
24
我认为你正在阅读的书是Herbert Schildt所写的C: The Complete Reference (C语言权威指南)。根据这本书的一篇评论(http://www.accu.informika.ru/accu/bookreviews/public/reviews/c/c002173.htm):“我不会推荐这本书(因为太多人过分看重我的意见),但我认为它没有像他其他一些作品那样受到公正抨击。”正如Michael所说,更好的参考书是Harbison & Steele (C程序设计语言)。 - Alok Singhal
1
我的建议是:由于char可以是无符号的,因此使用getchar()读取值时,通常使用int作为规则。 getchar()可能会返回EOFEOF通常定义为-1或其他负值,在unsigned中存储不是您想要的结果。这是声明:extern int getchar();顺便说一句,这个建议也来自于《C: A Reference Manual》书籍。 - Maxim Chetrusca
10
我信任的唯一一份C参考资料是ISO/IEC 9899:2011 :-) - Jeff Hammond
5
@MaxChetrusca 给出的建议不错,但是理由有误:即使在signed char的情况下,你也必须使用int来存储返回值。 - Antti Haapala -- Слава Україні
6个回答

263

这本书是错误的。标准并没有规定纯粹的char是有符号还是无符号。

实际上,标准定义了三种不同的类型:charsigned charunsigned char。如果你#include <limits.h>并查看CHAR_MIN,就可以知道纯粹的charsigned还是unsigned(如果CHAR_MIN小于0或等于0),但即使如此,就标准而言,这三种类型是不同的

需要注意的是,char在这方面是特殊的。如果你将一个变量声明为int,它与声明为signed int是完全等价的。对于所有编译器和架构来说,这一点始终如一。


10
是的,char是唯一可以有符号或无符号类型的数据类型。例如,int等同于signed int - Alok Singhal
44
这其中有一个历史上的原因,早期的 C 语言标准至少翻转了两次,一些流行的早期编译器最终采用了一种方式,而其他一些则采用了另一种方式。 - Hot Licks
12
一个类型为 int 的位域(bit field)是否有符号也是实现定义的。 - Keith Thompson
1
我想知道为什么ANSI还没有定义任何标准方式,使得代码可以表达诸如“在这个区域内,我希望编译器将char视为无符号或者如果不能这样做则拒绝编译”之类的内容?我理解标准必须允许存在不同方言的C语言,但是如果没有标准的方法来表达0xFFFF+1是否应该产生0u或65536,那么我认为这样的表达式应该被视为在“标准C”中毫无意义。 - supercat
1
@supercat: #if CHAR_MIN < 0 ... #error "Plain char is signed" ... #endif @supercat:#if CHAR_MIN < 0 ... #error“普通字符是有符号的” ... #endif - Keith Thompson
显示剩余9条评论

80

正如Alok所指出的,标准将其委托给实现。

对于gcc,默认值为signed,但可以使用-funsigned-char进行修改。注意: 对于Android NDK中的gcc,默认值为unsigned。你也可以使用-fsigned-char明确要求有符号字符。

在MSVC上,默认值为signed,但可以使用/J进行修改。


2
有趣的是,Schildt的描述与MSVC的行为不匹配,因为他的书通常面向MSVC用户。我想知道MS是否在某个时候更改了默认设置? - Michael Burr
2
我认为这不是依赖于编译器,而是依赖于平台。我认为char被留作第三种“字符数据类型”,以符合当时系统使用的可打印字符的标准。 - Spidey
15
GCC文档所述,这是与机器相关的:"每种类型的计算机都有一个 char 默认值。它可以是默认情况下的 unsigned char 或者是 signed char。" - Deduplicator
1
请问您能否提供一个关于在安卓上默认使用无符号字符的注释的来源? - phlipsy
2
@Deduplicator,所以这个答案中的“_对于gcc,默认值是有符号的_”部分是错误的吗? - Spikatrix
显示剩余3条评论

40

C99 N1256草案6.2.5/15 "类型"中关于类型char的有关签名的规定如下:

实现应定义char类型具有与signed charunsigned char之一相同的范围、表示和行为。

并在一个脚注中指出:

<limits.h>中定义的CHAR_MIN将具有值0SCHAR_MIN之一,这可以用于区分两个选项。无论做出何种选择,char都是与另外两个类型不兼容的独立类型。


10
根据Dennis Ritchie所著《C程序设计语言》这本ANSI C的事实标准书籍,原始字符无论是有符号还是无符号都取决于计算机,但可打印字符始终为正数。

13
可打印字符并非总是正数。C语言标准保证基本执行字符集的所有成员都具有非负值。 - Keith Thompson

10
根据C标准,普通字符(plain char)的符号性是“实现定义的”(implementation defined)。
一般来说,实现者会在他们的架构上选择更高效的方式。在x86系统中,char通常是有符号的。在arm系统中,char通常是无符号的(苹果iOS是一个例外)。

1
为什么在ARM中无符号类型更有效率?iOS中char默认是有符号还是无符号的? - phuclv
4
你的回答可能被点踩是因为Tim Post丢了他的钥匙。但是,只要你确定你的回答是正确的(在这种情况下它是正确的),就不必担心一个点踩。我的帖子也曾多次遭到无效点踩。别担心,有时人们做一些奇怪的事情。 - Donald Duck
2
为什么在x86上使用有符号字符更有效率?有任何来源吗? - martinkunev
3
@martinkunev 的留言有点过时,但我认为在 x86 架构中,signed char 并没有比 unsigned char 更有效率,但也不会比 unsigned char 低效。选择 signed char 的原因可能包括与其他整数类型默认使用有符号数相一致,有符号溢出的行为未定义,因此编译器可以假设它不会发生溢出,从而导致有时候有符号类型会更容易被优化。 - Arkku

4
现在,我们知道标准将这留给实现。但是如何检查类型是有符号还是无符号,例如 char?我编写了一个宏来完成此操作:
#define IS_UNSIGNED(t) ((t)~1 > 0)
并使用 gcc、clang 和 cl 进行测试。但我不确定它是否始终适用于其他情况。

6
通常情况下 CHAR_MIN < 0(或wchar_t类型的WCHAR_MIN < 0)有什么问题? - Öö Tiib
这基于有符号整数采用二进制补码表示的假设。虽然这几乎总是成立的,但某些系统可能使用一的补码,其中所有位设置为1表示负零,等于正零,而您的宏将返回错误的答案。 - z32a7ul

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