我找到了一个程序,可以打印有符号字符的最大值和最小值。虽然我们在课堂上学过位运算,但我不明白为什么要把所有的运算符放在一起。
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 char
比unsigned char
少一个值位,因为它的表示与unsigned char
的大小相同,都没有任何填充位,signed char
使用它的一个位作为符号位。右移一个位置将多余的值位移走,导致unsigned char
的值是signed char
类型所能容纳的最大值。
结果被强制转换为类型char
,这是没有意义的。转换后值不会改变,但是
char
与signed char
是不同的类型,前者不一定是有符号类型,因此转换为char
无论如何都不能满足与signed char
的值范围相关的任何目的。在传递给
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
所以表达式中操作数求值的顺序是:
- 计算
~0 >> 1
并将结果强制转换为unsigned char
, - 将之前的结果强制转换为
char
, - 使用
-
操作符和 改变先前结果的符号 - 减去1 (
-1
)得到可能的最小值(0
的值被认为是正值)