【问题标题】:Is char signed or unsigned by default?char 默认是有符号还是无符号?
【发布时间】:2022-01-03 20:08:49
【问题描述】:

在“C 的完整参考”一书中提到char 默认情况下是无符号的。

但我正在尝试使用 GCC 以及 Visual Studio 来验证这一点。它默认将其作为 已签名

哪个是正确的?

【问题讨论】:

  • 我信任的一本 C 参考书是 Harbison & Steele 的“C: A Reference Manual” (careferencemanual.com)。当然,标准是最终定论,但它的可读性不是很高,并且仅提供了有关标准之外的标准前和常见(即 POSIX)使用的最少量信息。 Harbison & Steele 非常易读、详细,并且可能比大多数参考资料更正确。但是它也不是教程,所以如果您处于学习的初始阶段,那么跳进去可能不是一件好事。
  • 我认为您正在阅读的书是 Herbert Schildt 的C: The Complete Reference。来自对这本书的评论 (accu.informika.ru/accu/bookreviews/public/reviews/c/c002173.htm):我不会推荐这本书(你们中的太多人过于重视我的观点),但我认为它不应该受到同样的谴责扔在他的一些其他工作。 正如迈克尔所说,一个更好的参考是 Harbison & Steele
  • 我的两分钱在这里:因为char 可以是无符号的,根据经验,使用int 来读取使用getchar() 的值,这可能会返回EOFEOF 通常定义为-1 或其他负值,存储在unsigned 中不是您想要的。声明如下:extern int getchar(); BTW,此建议也来自《C: A Reference Manual》一书。
  • 我信任的一个 C 参考是 ISO/IEC 9899:2011 :-)
  • @MaxChetrusca 好建议,但理由不好:即使在签名的 char 案例中,您也必须使用 int 来存储返回值。

标签: c types char signed


【解决方案1】:

这本书是错的。标准没有指定普通的char 是有符号还是无符号。

事实上,该标准定义了三种不同的类型:charsigned charunsigned char。如果你#include <limits.h>,然后查看CHAR_MIN,你可以发现普通charsigned还是unsigned(如果CHAR_MIN小于0或等于0),但即使这样, 就标准而言,三种类型是不同的

请注意char 在这方面是特殊的。如果您将变量声明为int,则它与将其声明为signed int 100% 等效。这对于所有编译器和架构都是如此。

【讨论】:

  • @Alok:对于其他一些数据类型,情况并非如此,例如int 总是意味着signed int,对吧?除了char,还有哪些数据类型在C中有同样的困惑?
  • @eSKay:是的,char 是唯一可以签名或未签名的类型。例如,int 等价于 signed int
  • 这有一个歇斯底里的,呃,历史原因——在 C 语言的早期,“标准”至少被翻转了两次,一些流行的早期编译器以一种方式结束,而另一些则以一种方式结束另一个。
  • @AlokSinghal:int 类型的位字段是有符号还是无符号也是实现定义的。
  • @supercat: #if CHAR_MIN < 0 ... #error "Plain char is signed" ... #endif
【解决方案2】:

作为Alok points out,标准将其留给实施。

对于 gcc,默认是签名的,但您可以使用 -funsigned-char 修改它。 注意:对于 Android NDK 中的 gcc,默认为无符号。您还可以使用-fsigned-char 明确要求签名字符。

在 MSVC 上,默认已签名,但您可以使用 /J 进行修改。

【讨论】:

  • 有趣的是,Schildt 的描述与 MSVC 的行为不符,因为他的书通常面向 MSVC 用户。我想知道 MS 是否在某个时候更改了默认值?
  • 我认为它不依赖于编译器,而是依赖于平台。我认为 char 被保留为第三种“字符数据类型”,以符合当时系统用作可打印字符的内容。
  • GCC docs 说它依赖于机器:“每种机器都有一个默认的 char 应该是什么。默认情况下它类似于 unsigned char 或默认情况下类似于 signed char。"
  • 您能否提供一个来源,说明您在 android 上的默认值是 unsigned char?
  • @Spidey C 标准没有真正区分编译器、平台和 CPU 架构。它只是将它们放在“实施”下。
【解决方案3】:

C99 N1256 draft 6.2.5/15 "Types" 对char 类型的签名有这样的说法:

实现应将 char 定义为与有符号字符或无符号字符具有相同的范围、表示和行为。

并在脚注中:

CHAR_MIN,在<limits.h> 中定义,将具有0SCHAR_MIN 值之一,这可用于区分这两个选项。无论做出何种选择,char 都是与其他两个不同的类型,并且与任何一个都不兼容。

【讨论】:

    【解决方案4】:

    根据 Dennis Ritchie 所著的 The C Programming Language book 是 ANSI C 的事实上的标准书,有符号或无符号的纯字符取决于机器,但可打印的字符始终是正数。

    【讨论】:

    • printable 字符不一定都是正数。 C 标准保证基本执行字符集的所有成员都具有非负值。
    【解决方案5】:

    根据 C 标准,普通字符的符号是“实现定义的”。

    一般来说,实施者会选择在他们的架构上实施更有效的方法。在 x86 系统上,char 通常是有符号的。在 arm 系统上,它通常是未签名的(Apple iOS 是一个例外)。

    【讨论】:

    • @plugwash 您的回答可能被否决了,因为Tim Post lost his keys。不过说真的,只要您确定您的答案是正确的(在这种情况下就是这样),您就不必担心一次投反对票。我的帖子无缘无故被否决了好几次。不用担心,有时人们只是做些奇怪的事情。
    • 为什么 signed char 在 x86 上更高效?有什么来源吗?
    • @martinkunev Necropost 但是:我不认为有符号的字符在 x86 上更有效,但它的效率也不比无符号低。选择它的原因可能还包括与其他默认为有符号的整数类型的一致性,并且可能有符号类型有时会导致更好的优化,因为有符号溢出是未定义的行为(即编译器可以假设它不会溢出)。
    【解决方案6】:

    现在,我们知道标准将其留给实施。

    但是如何检查一个类型是signed还是unsigned,比如char

    为此我编写了一个宏:

    #define IS_UNSIGNED(t) ((t)~1 > 0)

    并使用gccclangcl 对其进行测试。但我不确定它对于其他情况是否总是安全的。

    【讨论】:

    • 通常的 CHAR_MIN
    猜你喜欢
    • 2019-09-10
    • 2010-12-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多