为什么C和C++如此讨厌签名字符
Why C and C++ hate signed char so much?
为什么C允许使用"字符类型"访问对象:
6.5 表达式(C)
对象的存储值只能由具有以下类型之一的左值表达式访问:
- 字符类型。
但是C++只允许字符和无符号字符?
3.10 左值和右值(C++)
如果程序尝试通过以下类型之一以外的 glvalue 访问对象的存储值,则行为是未定义的:
- 字符或无符号字符类型。
签名字符仇恨的另一部分(引用自C++标准):
3.9 类型(C++)
对于简单可复制类型 T 的任何对象(基类子对象除外),无论该对象是否具有 T 类型的有效值,都可以将构成该对象的基础字节复制到char或无符号字符数组中。如果将 char 数组或无符号 char的内容复制回对象,则对象随后应保持其原始值。
从 C 标准:
6.2.6 类型(C)的表示
存储在任何其他对象类型的非位字段对象中的值由 n 位× CHAR_BIT组成,其中 n 是该类型的对象的大小(以字节为单位)。该值可以复制到无符号字符[n] 类型的对象中(例如,通过 memcpy);生成的字节集称为值的对象表示形式。
我可以看到很多人在stackoverflow上说这是因为无符号char是唯一保证没有填充位的字符类型,但是C99节6.2.6.2整数类型说
签名字符不得有任何填充位
那么这背后的真正原因是什么呢?
以下是我对动机的看法:
在非二进制补码系统上,signed char
不适合访问对象的表示。这是因为有两种可能的signed char
表示具有相同的值(+0 和 -0),或者有一个没有值的表示(陷阱表示)。无论哪种情况,这都会阻止您执行可能对对象的表示形式执行的最有意义的操作。例如,如果你有一个 16 位无符号整数0x80ff
,一个或另一个字节,作为signed char
,将捕获或比较等于 0。
请注意,在这样的实现(非二进制补码)上,需要将纯char
定义为无符号类型,以便通过char
访问对象的表示才能正常工作。虽然没有明确的要求,但我认为这是从标准中的其他要求派生出来的要求。
我认为你真正要问的是为什么signed char
被取消了所有允许类型双关语作为特例char*
的规则的资格。老实说,我不知道,特别是因为——据我所知——signed char
也不能有填充:
[C++11: 3.9.1/1]:
[..]char
、signed char
和unsigned char
占用相同的存储量并具有相同的对齐要求 (3.11);也就是说,它们具有相同的对象表示形式。对于字符类型,对象表示形式的所有位都参与值表示形式。[..]
经验证据表明,它只不过是惯例:
char
被视为 ASCII 的一个字节;unsigned char
被视为具有任意"二进制"内容的字节;signed char
在风中飘扬。
对我来说,将其排除在这些标准规则之外似乎还不足以成为理由,但老实说,我找不到任何相反的证据。我将把它归结为标准措辞中一个稍微莫名其妙的奇怪之处。
(可能我们必须向std-discussion
列表询问这个问题。
使用字符类型来检查对象的表示是一种黑客。但是,这是历史性的,必须做出一些调整才能允许它。
大多数情况下,在编程语言中,我们想要强类型。作为float
的东西应该作为float
而不是int
访问。这有很多好处,包括减少人为错误和实现各种优化。
但是,有时需要访问或修改对象的字节。在 C 语言中,这是通过字符类型完成的。C++延续了这一传统,但通过消除为此目的使用signed char
,情况略有改善。
理想情况下,最好创建一个新类型,例如byte
,并仅允许通过此类型对对象表示进行字节访问,从而将常规字符类型分开,仅用作普通整数/字符。也许有人认为有太多的现有代码使用char
和unsigned char
来支持这样的更改。但是,我从未见过用于访问对象表示signed char
,因此将其排除是安全的。
- C++字符*缓冲区的大小
- HEX值到wchar_t字符(UTF-8)的转换
- 为什么 Serial.println(<char[]>);返回随机字符?
- 我的字符计数代码计算错误.为什么
- 字符串-C++后显示的随机字符
- 将Integer转换为4字节的unsined字符矢量(按大端字节顺序)
- 如何在C++中从字符串中分割字符
- 为什么msgrcv()将垃圾字符馈送到缓冲区
- 指向指向字符数组的指针数组的指针
- 如何用转义符替换字符串中的所有特殊字符
- 为什么 sscanf 无法从一个字符串中读取uint64_t和字符?
- 比较字符数组
- 将字符指针十六进制转换为字符串并保存在文本文件C++中
- 从矢量<无符号字符>转换为字符* 包括垃圾数据
- 如何使用Crypto++并为RSA返回可打印的字节/字符数组
- 如何在C++中确定文本文件中的元素是字符还是数字
- 如何将一个ostringstream十六进制字符串字符对转换为单个unit8t等价的二进制值
- 为字符串中每 N 个字符插入空格的函数没有按照我认为的方式工作?
- C++中无符号字符溢出
- 为什么C和C++如此讨厌签名字符