【问题标题】:Bitwise operations w/ signed chars带符号字符的按位运算
【发布时间】:2016-09-25 07:47:46
【问题描述】:

我找到了一个打印有符号字符的最大值和最小值的程序。虽然我们在课堂上学过位运算,但我不明白什么时候把所有的运算符放在一起。

 int main(void)
    {
        printf("Minimum Signed Char %d\n",-(char)((unsigned char) ~0 >> 1) - 1);
        printf("Maximum Signed Char %d\n",(char) ((unsigned char) ~0 >> 1));
    }

例如,我知道 ~ 翻转位并 >> 将它们移到右侧。所以我相信〜0 >> 1,翻转所有位并将它们移到正确的一个位置。但是为什么我们要减去 1,我以为二进制补码加一呢?

【问题讨论】:

  • 这是“实现未定义的行为”,即它依赖于实现定义的行为,但实现可能会定义它是未定义的行为。如果您的目标是打印 char 的最大值和最小值,请执行 #include <limits.h> 并打印出 CHAR_MINCHAR_MAX

标签: c bit-manipulation


【解决方案1】:
  • (unsigned char) ~0 的所有位都为 1(最大正数 unsigned char
  • >> 1 关闭最高位,用于符号(最大正数signed char
  • -(char) 将该值否定为char(注意:应该是signed char
  • - 1 用于现在的负值,因为在二进制补码中,最负值的幅度比最正值大一(因为零值的符号位已关闭,并且二进制补码中没有“负零”补充)

【讨论】:

    【解决方案2】:

    先取最大值,在原表达式后面加括号明确运算顺序,原表达式变为

    (char) (((unsigned char) (~0)) >> 1)
    

    首先,~0 产生一个int 类型的值(因为常量0 具有该类型),其位模式由所有1s(不包括任何填充位)组成。这将是一个负数,因为它的符号位将被设置。

    强制转换将该值转换为unsigned char 类型,从而生成该类型的所有位为1 的值。

    但是signed char 类型的值位正好比unsigned char 少一个,因为它的表示与unsigned char 的大小相同,也没有任何填充位,并且signed char 使用它的一个位作为符号位。右移一位会移出额外的值位,从而产生一个unsigned char,其值是signed char 类型可以容纳的最大值。

    然后将结果转换为类型char,这是没有意义的。该值将不会因转换而改变,但

    1. char 是与signed char 不同的类型,前者不一定是有符号类型,因此转换为char 无论如何都不能用于与signed char 的值范围相关的任何目的。

    2. 生成的表达式将被转换(进一步)为类型int,然后再将其传递给printf()

    尽管如此,显示的值确实是可表示为signed char 的最大值。


    最小值的表达式只产生比最大值的倒数小一的结果。这是正确的最小值,前提是signed char 以二进制补码形式表示。尽管我知道的每个现代实现确实确实对有符号整数使用二进制补码形式,但 C 明确允许其他两种形式,这两种形式的最小值都等于它们最大值的倒数。该程序会在具有signed char 表示的平台上生成错误的最小值。

    【讨论】:

      【解决方案3】:

      因为零被认为是正数,所以有 128 个正值 0 到 127 但是负数从 -1 开始,所以它有 128 个负值 -1 到 - 128。

      简单地说,正数从 0 开始,所以它只到 127,而负数从 -1 开始,所以它到 -128

      这就是为什么 0111111 = 127 但 1000000=-128;

      【讨论】:

      • 零不被认为是正数
      • @M.M 在他的例子中是!!!我的回答是正确的,为什么他们在他的例子中不能相互补充。
      【解决方案4】:

      在用于计算最小值的表达式前面有一个- 运算符:

      -(char)((unsigned char) ~0 >> 1) - 1
      

      所以表达式中操作数计算的顺序是:

      1. 计算~0 >> 1并将结果转换为unsigned char
      2. 将之前的结果转换为char
      3. 使用- 运算符和
      4. 更改先前结果的符号
      5. 减一 (-1) 以获得最小可能值(0 值被视为正值)。

      【讨论】:

        猜你喜欢
        • 2013-05-23
        • 2012-11-12
        • 1970-01-01
        • 2013-07-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-04-21
        • 1970-01-01
        相关资源
        最近更新 更多