关于char的签名问题

Issues about the signedness of char

根据标准,char是否签名是实现定义的。这给我带来了一些麻烦。以下是一些示例:

1) 测试最高有效位。如果 char 已签名,我可以简单地将值与 0 进行比较。如果未签名,我会将值与 128 进行比较。这两种简单方法都不是通用的,适用于两种情况。为了写出可移植的代码,貌似要直接操作位,不太整洁

2) 赋值。有时,我需要将位模式写入 char 值。如果 char 是无符号的,这可以使用十六进制表示法轻松完成,例如 char c = 0xff。但是这个方法在char签名时不适用。以 char c = 0xff 为例。 0xff 超出了有符号 char 可以容纳的最大值。在这种情况下,标准表示 c 的结果值是实现定义的。

那么,有没有人对这两个问题有好的想法?关于第二个,我想知道 char c = '\xff' 是否适用于有符号和无符号 char

注意: 有时需要将明确的位模式写入字符。请参阅 http://en.cppreference.com/w/cpp/string/multibyte/mbsrtowcs 中的示例。

其实你可以做你想做的事而不用担心签名。

十六进制描述位模式而不是整数值。 (见免责声明)

所以对于 2. 你说你不能像这样分配位模式

char c = 0xff

但你真的可以做到,无论是否签名。

对于 1,您可能无法执行 "compare with 0" 技巧,但您仍然有多种方法来检查最高有效位。一种方法是,向右移动 7,向左移动零,然后检查它是否等于 1。与符号无关。

正如 Tony D 指出的那样,(x | 0x7F) != 0x7F 是一种比移位更便携的方法,因为它可能不会移位到零。类似地,你可以做 x & 0x80 == 0x80.

当然你也可以按照 Brian 的建议,只使用一个 unsigned char。

免责声明:Tony 指出 0x 实际上是一个 int,当 char 不能保存值或 char 是无符号时,转换为 char 是实现定义的。但是,没有任何实现会破坏这里的标准。 char c = 0xFF,天气或未签名与否,将填充这些位,相信我。很难找到不这样做的实现。

您可以将给定值与 0x7F0xFF 分别进行 OR 和 AND 以检测并删除其 signed_ness.

1) 测试 MSB:(x | 0x7F) != 0x7F(或 reinterpret_cast<unsigned char&>(x) & 0x80

2) reinterpret_cast<unsigned char&>(x) = 0xFF;

请注意,如果您想将字符占用的内存视为位集合,绕过与 char 类型中任何给定值关联的特定位模式,则 reinterpret_cast 是完全合适的。

如果您真的很在意符号性,只需根据需要将变量声明为 signed charunsigned char 即可。不需要平台无关的位技巧。

测试 MSB 的最简单方法是将其设为 LSB:char c = foo(); if ((c>>(CHAR_BIT-1)) & 1) ...

设置特定的位模式有点棘手。例如,全位一可能不一定是 0xff,但也可能是 0x7ff,或者更现实地说是 0xffff。无论如何,~char(0) 是全位一。不太明显,char(-1) 也是如此。如果 char 有符号,那很清楚;如果无符号这仍然是正确的,因为无符号类型工作模 2^N。按照该逻辑,char(-128) 仅设置 8 位,而不管 char 中有多少位或是否已签名。