C 带符号字符的位运算

C 带符号字符的位运算,c,bit-manipulation,C,Bit Manipulation,我发现了一个程序,可以打印有符号字符的最大值和最小值。虽然我们在课堂上学习了位运算,但我不明白什么时候所有的运算符都放在一起了 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 >>

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

 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,我认为2的补码加1呢

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

-(char)((unsigned char) ~0 >> 1) - 1
因此,表达式中操作数求值的顺序为:

  • 计算
    ~0>>1
    并将结果强制转换为
    无符号字符
  • 将上一个结果强制转换为
    char
  • 使用
    -
    运算符和更改上一个结果的符号
  • 减去一(
    -1
    )以获得最小可能值(
    0
    值被视为正值)
    • (无符号字符)~0
      具有所有位1(最大正
      无符号字符
    • >1
      关闭用于符号的最高位(最大正数
      有符号字符
    • -(char)
      将该值作为
      char
      求反(注意:应为
      带符号的char
    • -1
      用于现在的负值,因为在二的补码中,最负的值的大小比最正的值大一个(因为零的值具有符号位,并且二的补码中没有“负零”)

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

    简而言之,正值从0开始,所以它只能得到127,而负值从-1开始,所以它可以得到-128


    这就是为什么011111=127,但1000000=-128

    首先取最大值,在原始表达式中添加括号以澄清运算顺序,原始表达式变为

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

    强制转换将该值转换为类型
    无符号字符
    ,这将导致该类型的值具有所有位
    1

    但是类型
    有符号字符
    的值位正好比
    无符号字符
    少一个,因为它的表示与
    无符号字符
    的表示大小相同,没有任何填充位,
    有符号字符
    使用它的一个位作为符号位。将右移一个位置会使附加值位偏移,从而产生一个
    无符号字符
    ,其值是类型
    有符号字符
    可以容纳的最大值

    然后将结果转换为类型
    char
    ,这是毫无意义的。转换后该值将保持不变,但

  • char
    signed char
    是不同的类型,前者不一定是有符号类型,因此强制转换到
    char
    无论如何都不能用于与
    signed char
    的值范围相关的任何用途

  • 在将结果表达式传递给
    printf()
    之前,它将(进一步)转换为类型
    int

  • 然而,显示的值实际上是可表示为
    有符号字符的最大值



    最小值的表达式只比最大值的倒数少一个。这是正确的最小值,前提是
    有符号字符
    以二的补码形式表示。虽然我所知道的每个现代实现确实使用2的补码形式表示有符号整数,但C明确允许使用另外两种形式,这两种形式的最小值都等于其最大值的倒数。该程序将在平台上生成错误的最小值,该平台具有
    带符号字符

    的表示形式,这是“未定义的实现行为”,即它依赖于实现定义的行为,但实现可能会定义它是未定义的行为。如果您的目标是打印
    字符的最大值和最小值
    ,请执行
    #包括
    并打印出
    字符最小值
    ,并且不考虑
    字符最大值
    为零positive@M.M在他的例子中是!!!我的答案是正确的,关于为什么在他的例子中它们不能相互补充。