【问题标题】:Issues about the signedness of char关于 char 的签名问题
【发布时间】:2015-03-26 02:30:12
【问题描述】:

根据标准,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 中的示例。

【问题讨论】:

  • 如果您关心位模式,也许您应该始终使用unsigned char
  • 我只使用 char 作为字符,或者因为我必须(流等)如果我想要一些数字,而这些数字恰好是一个字节大小,我总是使用显式签名字符。
  • 有时,需要的是一个字符串。但是,应明确指定字符的值。请参阅en.cppreference.com/w/cpp/string/multibyte/mbsrtowcs 中的示例。
  • 测试 MSB:(x | 0x7F) != 0x7F
  • 我真的不明白你测试 MSB 的理由。无符号和有符号的 MSB 位相同。

标签: c++ char language-lawyer signedness


【解决方案1】:

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

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

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

【讨论】:

  • 对于 1) 我认为 (unsigned char)c >= 128 更干净。对于2),字符串怎么样?我需要明确指定字符串中字符的位模式,如 en.cppreference.com/w/cpp/string/multibyte/mbsrtowcs 的示例
  • 对于 1),if (c & 0x80) 似乎是最干净的。不管c被提升为有符号还是无符号都是正确的。
  • @Lingxi:我之所以使用 0x7F 是因为它是不言而喻的正确...如果您甚至要问c & 0x80是否也正确,那么您不应该使用它,因为-在最好 - 以后查看您的代码的每个程序员都可能想知道同样的事情。
  • 也就是说,令人担忧的情况是char 有符号时,相关段落来自 5/10 “如果两个操作数都具有有符号整数类型或都具有无符号整数类型,则带有较小整数转换等级的类型应转换为具有较大等级的操作数的类型。”,因此字符c被提升为signed int类型0x80。如果系统碰巧使用二进制补码整数表示,则 0x80 处的位将保持设置。如果它使用符号/大小表示,符号位将移动到最高有效位。所以,它是不​​可靠的。
【解决方案2】:

如果您真的关心签名,只需根据需要将变量声明为signed charunsigned char。不需要独立于平台的位旋转技巧。

【讨论】:

    【解决方案3】:

    您可以将给定的值分别与两个0x7F0xFF 进行 OR 和 AND 以检测和删除其signed_ness。

    【讨论】:

      【解决方案4】:

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

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

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

      字符 c = 0xff

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

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

      正如 Tony D 指出的那样,(x | 0x7F) != 0x7F 是一种更便携的方法,而不是移位,因为它可能不会移位为零。同样,您可以执行 x & 0x80 == 0x80。

      当然,您也可以按照 Brian 的建议进行操作,只使用无符号字符。

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

      【讨论】:

      • "您仍然可以向右移动 7,然后检查它是否等于 1" - 标准定义了负值实现的右移,因此不能保证将可移植(5.8/3“如果 E1 具有带符号类型和负值,则结果值是实现定义的。”)
      • 我认为从int 分配到char 属于 4.7/3 “如果目标类型是有符号的,那么如果它可以在目标类型(和位字段)中表示,则值不变width);否则,该值为 implementation-defined。"
      • char c = 0xFF 如果 char 已签名,则由实现定义
      【解决方案5】:

      测试 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 中有多少位或是否有符号。

      【讨论】:

        猜你喜欢
        • 2011-06-11
        • 2011-04-29
        • 2012-05-23
        • 2012-11-19
        • 2022-01-06
        • 2020-05-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多