为什么C允许使用“字符类型”访问对象:
6.5表达式(C)
对象的存储值只能由具有以下类型之一的左值表达式访问:
- 字符类型。
但是C ++只允许 char 和 unsigned char ?
3.10 Lvalues and rvalues (C ++)
如果程序试图通过以下类型之一以外的glvalue访问对象的存储值,则行为未定义:
- char或unsigned char类型。
签名字符仇恨的另一部分(引自C ++标准):
3.9类型(C ++)
对于普通可复制类型T的任何对象(基类子对象除外),无论对象是否保持类型T的有效值,构成对象的基础字节都可以复制到 char 或 unsigned char 。如果将 char 或 unsigned char 数组的内容复制回对象,则该对象应随后保持其原始值。
从C标准:
6.2.6类型表示(C)
存储在任何其他对象类型的非位字段对象中的值由n×CHAR_BIT位组成,其中n是该类型对象的大小(以字节为单位)。可以将该值复制到 unsigned char [n]类型的对象中(例如,通过memcpy);生成的字节集称为值的对象表示。
我可以看到很多人在stackoverflow上说这是因为 unsigned char 是唯一保证没有填充位的字符类型,但是C99 Section 6.2.6.2整数类型说
signed char不应有任何填充位
那背后的真正原因是什么?
答案 0 :(得分:15)
这是我对动机的看法:
在非二进制补码系统上,signed char
将不适合访问对象的表示。这是因为有两个可能的signed char
表示具有相同的值(+0和-0),或者一个表示没有值(陷阱表示)。在任何一种情况下,这都会阻止您对对象的表示执行最有意义的操作。例如,如果您有一个16位无符号整数0x80ff
,则一个或另一个字节(signed char
)将陷阱或比较等于0。
请注意,在这样的实现(非二进制补码)上,普通char
需要定义为无符号类型,以便通过char
访问对象的表示以使其正常工作。虽然没有明确的要求,但我认为这是从标准中的其他要求中得出的要求。
答案 1 :(得分:8)
我认为你真正要问的是为什么signed char
被取消所有允许打字char*
作为特例的规则的资格。说实话,我不知道,特别是因为 - 据我所知 - signed char
也不能填充:
[C++11: 3.9.1/1]:
[..]char
,signed char
和unsigned char
占用相同数量的存储空间并具有相同的存储空间对准要求(3.11);也就是说,它们具有相同的对象表示。对于字符类型,对象表示的所有位都参与值表示。 [..]
Empirical evidence suggests that it's not much more than convention:
char
被视为ASCII的字节; unsigned char
被视为具有任意“二进制”内容的字节;和signed char
在风中飘扬。对我而言,似乎没有理由将其排除在这些标准规则之外,但老实说,我找不到任何相反的证据。我将在标准措辞中将其归结为一种轻微莫名的怪异。
(可能我们必须询问std-discussion
列表。)
答案 2 :(得分:7)
使用字符类型来检查对象的表示是一种破解。但是,它是历史性的,必须有一些条件允许它。
大多数情况下,在编程语言中,我们需要强类型。属于float
的内容应以float
而非int
的形式进行访问。这有许多好处,包括减少人为错误和实现各种优化。
但是,有时需要访问或修改对象的字节。在C中,这是通过字符类型完成的。 C ++延续了这一传统,但它通过消除signed char
用于这些目的而略微改善了这种情况。
理想情况下,最好创建一个新类型,比如byte
,并允许仅通过此类型对对象表示进行字节访问,从而将常规字符类型分开,仅用作普通整数/字符。也许有人认为使用char
和unsigned char
来支持此类更改的现有代码太多了。但是,我从未见过signed char
用于访问对象的表示形式,因此可以安全地将其排除。