C语言 带符号字符的按位操作



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

 int main(void)
    {
        printf("Minimum Signed Char %dn",-(char)((unsigned char) ~0 >> 1) - 1);
        printf("Maximum Signed Char %dn",(char) ((unsigned char) ~0 >> 1));
    }
例如,我知道~翻转位,而>>将它们向右移动。所以我相信~0>> 1,翻转所有位并将它们移到右一个位置。但是为什么要减1,我以为2的补加1呢?
  • (unsigned char) ~0全部为1位(unsigned char最大正位)
  • >> 1关闭最高位,用于符号(最大正signed char)
  • -(char)将该值作为char(注意:应该是signed char)否定
  • - 1用于现在为负值的值,因为在二进制补码中,最负的值比最正的值大1(因为0的值有符号位,并且在二进制补码中没有"负0")

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

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

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

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

但是类型signed charunsigned char少一个值位,因为它的表示与unsigned char的大小相同,都没有任何填充位,signed char使用它的一个位作为符号位。右移一个位置将多余的值位移走,导致unsigned char的值是signed char类型所能容纳的最大值。

结果被强制转换为类型char,这是没有意义的。转换后值不会改变,但是

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

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

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


最小值的表达式只产生比最大值的倒数小1。这是正确的最小值,前提是signed char以二进制补码形式表示。尽管我所知道的每个现代实现确实都使用2的补码形式来表示有符号整数,但C明确地允许另外两种形式,这两种形式的最小值都等于最大值的倒数。该程序将在具有这样的signed char表示的平台上产生错误的最小值。

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

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

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

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

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

所以表达式中操作数求值的顺序是:

  1. 计算~0 >> 1并将结果强制转换为unsigned char
  2. 将之前的结果强制转换为char
  3. 使用-操作符和
  4. 改变先前结果的符号
  5. 减去1 (-1)得到可能的最小值(0的值被认为是正值)

最新更新