C语言编程题(二)运算符与位运算符优先级

#include 

int main()
{
unsigned char a=0xa5;
unsigned char b=~a>>4+1;
printf("b=%d",b);
return 0;

}

错误思路:

unsigned char占一个字节,即8bit,将a写入内存中的形式为:

1010 0101

按照常规来说,将a取反为

0101 1010

然后再右移动5个为

0000 0010

结果为2。

但是这里特别要注意一点,低于int类型(即规定的寄存器大小)的基础类型需要在运算过程中转化为int类型(寄存器的位数)的大小进行计算(为了保证运算的一致性和精确性,编译器会将较小的整数类型自动提升为int类型,并在进行运算时使用int类型的规则),然后在运算完成以后再截取成原大小进行结果的表示,所以这里的过程应该改为:

正确思路:

1010 0101

在16bit的寄存器中转化为

0000 0000 1010 0101

全部取反得到

1111 1111 0101 1010

而后右向移动5个,左边补0:

0000 0111 1111 1010

运算完成,开始从右边截取出unsigned char对应位数的值

1111 1010

该数值为内存中对应数字的补码形式,但是由于是unsigned型,所以相当于可以直接取用为原码形式:

即250

这里补充一个取反操作的知识点,我们在学习取反~这个操作

初学者在没有了解内存是如何存储数据的情况下往往会发现

取反之后读取内存中的数字有的时候是需要对内存中的数字取反加一再补负号

而有一些则直接取出当成结果就好,这是为什么呢?

1.一个数字存入内存中的时候,不是直接转为二进制直接存储的,编译器需要把当前数字转化为其对应的补码存入内存当中:正数的补码就是其原码(即其本身),而负数则需要对其取绝对值再加一。

例1.

-5(char型)转化为补码的方式为首先转为绝对值:

0000 0101 接着取反

1111 1010 再加1

1111 1011 这就是-5在内存中的表现形式

例2.

5的原码为0000 0101,其补码也为0000 0101

2.在内存中,若当前数字的补码最高位为1:表示这个数字为一个负数;需要取出这个数字的时候就需要首先对这个数字进行取反然后加一再补负号还原这个数字

在内存中,若当前数字的最高位为0:则这个数字表示一个正数,不需要转化可以直接取出来使用

例1.

需要把-5这个数字从内存中取出

1111 1011 首先取反

0000 0100 然后加一

0000 0101表示5,再补符号

-5 取出成功

例2.

在内存中取出5这个数字:

0000 0101

直接取出的到5即可

3.如何判断当前数字在取反后从内存取出时应不应该执行取反加一再加符号的操作:根据上面两条,由于取出数字是在内存当中执行的,所以我们要在取出的时候查看当前数字最高位是否是1,若发现当前数字在完成取反操作以后结果最高位为1是负数,则需要取反加一,反之不需要。

例1.

-5在内存当中表示

1111 1011 进行取反操作得到

0000 0100 编译器判断当前数字取反以后变成了正数,在取出这个数字时就不需哟取反加一了

结果就是4

例2.

5在内存中表示为

0000 0101 取反操作

1111 1010 编译器判断高位为1是负数,则需要取反加一补符号

0000 0101 先取反然后再加1

0000 0110的到结果6再补符号

~5的结果为-6

====================================================================================

其实这里也可以直接记成~-5前面是减号,就是5-1=4,结果就是4

~5的前面是正号,就是-(5+1)=-6

标签: 位运算

原文关于unsigned char的取反操作 - 雾漫大武汉 - 博客园 (cnblogs.com)

你可能感兴趣的:(c语言)