关于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,天气或未签名与否,将填充这些位,相信我。很难找到不这样做的实现。
您可以将给定值与 0x7F
和 0xFF
分别进行 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 char
或 unsigned 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 中有多少位或是否已签名。
根据标准,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,天气或未签名与否,将填充这些位,相信我。很难找到不这样做的实现。
您可以将给定值与 0x7F
和 0xFF
分别进行 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 char
或 unsigned 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 中有多少位或是否已签名。