随笔-80  评论-24  文章-0  trackbacks-0
首先看以下一段代码:
1 #include <cstdio>
2 
3 int main()
4 {
5     unsigned char t = 0xa5;
6     unsigned char i = (~t)>>4;
7     printf("%x\n", i);
8     return 0;
9 }

建议最好仔细先想一下再往下看

对于char、bool、unsigned char等低于int字节数的类型,进行运算的时候首先进行提升,因此在进行~t运算之前,先要将其放入32位寄存器,由于是unsigned char,因此前面补位全补0,因此0xa5-->0x000000a5,然后取反为0xffffff5a,然后再向右移四位为0xfffffff5,然后再转化为unsigned char型的0xf5赋值给i,因此最后输出结果为0xf5

再看下面这段代码:
1 #include <cstdio>
2 
3 int main()
4 {
5     char t = 0xa5;
6     char i = (~t)>>4;
7     printf("%x\n", i);
8     return 0;
9 }

思想和上面的完全相同,还是先提升为int然后再进行运算,但是注意这里是char型,因此提升的时候应该是根据最高位进行提升,最高位为1则前面全补全为1,否则全补全为0。因此再进行~t操作前应该先补全为0xffffffa5,然后进行取反操作为0x0000005a,然后再右移四位为0x00000005,再转化成char型的0x05赋值给i,因此最后结果为0x5

再看最后一个例子:
 1 #include <cstdio>
 2 
 3 int main()
 4 {
 5     char a = 0x80;
 6     char b = 0x2;
 7     unsigned char c = 0x80;
 8     unsigned char d = 0x2;
 9     printf("%x\n", a / b);
10     printf("%x\n", c / d);
11     return 0;
12 }
13 

主要是巩固前面说过的情况,非常类似,进行运算之前,a、b、c、d都要先补齐为:
a--->0xffffff80
b--->0x00000002
c--->0x00000080
d--->0x00000002
然后再进行运算,因此结果为:
0xffffffc0
0x40

最后再总结一下:unsigned char、char、bool等低于int型的类型,进行运算的时候都要先提升再运算,提升时根据signed和unsigned,在前面补位为0或者1,若是unsigned,则直接前面全补0;若为signed,则根据最高位为0还是1,若为0则全部补位为0,若为1则全部补位为1。
posted on 2011-04-07 01:26 myjfm 阅读(3446) 评论(16)  编辑 收藏 引用 所属分类: c/c++基础

评论:
# re: 取反操作的细节问题 2011-04-07 09:14 | 笨笨
Good. 反汇编一下,也能看到细节  回复  更多评论
  
# re: 取反操作的细节问题 2011-04-07 09:17 | clwahaha
哈! 以前都不知道的, 谢谢分享 学习了! 3q  回复  更多评论
  
# re: 取反操作的细节问题[未登录] 2011-04-07 09:30 | myjfm
@笨笨
反汇编确实可以了解到细节~  回复  更多评论
  
# re: 取反操作的细节问题 2011-04-07 09:40 | zuhd
只有把这个内存变量放到寄存器的时候才这么做吗?
还有,
char a = 0x80;
变成了a--->0xffffff80
这两个值也不相等啊,这么算出来的结果有啥意义呢?  回复  更多评论
  
# re: 取反操作的细节问题 2011-04-07 13:13 | myjfm
@zuhd
对于32位整型,0xffffff80是-128的补码吧?
而对于8位整型,0x80也是-128的补码吧?

另外,所以算数运算都是在寄存器中进行的吧?而现在32位机的寄存器都是32位的,所以才会存在整型提升问题,我是这么理解的~  回复  更多评论
  
# re: 取反操作的细节问题 2011-04-07 16:10 | zuhd
基本明白你要表达的意思了,不过我觉得你表达的不清楚,可以这样理解不:
不够32bit的数据类型,高位自动补齐,至于高位补的是0还是1,有以下的判断:
1,无符号数补0
2,有符号数看最高位标记,标记为0,存储正数,则补0,标记为1,则补1,理由是它存储的是一个负数的补码。
  回复  更多评论
  
# re: 取反操作的细节问题 2011-04-07 16:23 | zuhd
严格的讲
对于8bit的0x80也不能说是十进制-128的补码吧,最多说是10000000B的补码,当然进行逻辑运算的结果不会有错,如果补齐后最后截取低8bit的数据是
1000000B的话,我可能会说它是0,不知道理解有错没?  回复  更多评论
  
# re: 取反操作的细节问题 2011-04-07 21:57 | myjfm
@zuhd
不知道你说的这段话和我文章最后一段有什么区别阿?  回复  更多评论
  
# re: 取反操作的细节问题 2011-04-07 22:04 | myjfm
@zuhd
对于八位有符号数,能表示的数的范围不就是-128~127吗?-128不是0x80吗?
10000000B作为有符号数的补码来说怎么会是0的补码呢?好好看看计算机组成原理吧~  回复  更多评论
  
# re: 取反操作的细节问题 2011-04-08 08:57 | zuhd
@myjfm
我去 我一直以为10000000B是-0
难道-0就是-128吗?从理论上讲不对啊,但是它加上1后确实等于-127
--!  回复  更多评论
  
# re: 取反操作的细节问题 2011-04-08 10:00 | myjfm
@zuhd
对于有符号数来说:
如果是原码:00000000b是+0,10000000b是-0
如果是反码:00000000b是+0,11111111b是-0
而对于补码:00000000b是+0也是-0

下面是二进制代码与补码的对应:

00000000 +0/-0
00000001 +1
...
01111111 +127
10000000 -128
10000001 -127
...
11111110 -2
11111111 -1
从计组书上copy下来的~  回复  更多评论
  
# re: 取反操作的细节问题 2011-04-08 10:47 | zuhd
在8bit下存储-129,也不是不能存储,但只是高位会被截取而已,所以存储的数据可能就不是-129了,如果非得说10000000b是-128,
我顶多理解它是一个约定,因为128用除去最高位之后剩余的7bit根本无法存储,存储的也是截取后的低7位,7个0。  回复  更多评论
  
# re: 取反操作的细节问题 2011-04-08 11:38 | myjfm
@zuhd
既然高位已经被截取了那还怎么说“不是不能存储”呢?
求补码的过程本来就要把最高位符号位也用于计算
最高位符号位除了表示这个数是正是负外还有数值上的意义,它的作用不单单是符号位
所以你看-128的时候不能把最高位去掉再去看剩余7bit,要8个bit一起看~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  回复  更多评论
  
# re: 取反操作的细节问题 2011-04-08 13:57 | zuhd
我们可以按照 mod 128来理解,即
-129 与 -1的补码是相同的
-130 与-2的补码也是相同的
那么
-128与-0或是0的补码应该也是相同的
那为什么不说
11111111是-129的补码呢,
却说是-1的补码呢?
这8个bit完全能胜任-129的所有的存储信息
所以我坚持认为10000000b是-128的补码是个约定,请指教  回复  更多评论
  
# re: 取反操作的细节问题 2011-04-08 14:43 | myjfm
@zuhd
补码本身就是个约定  回复  更多评论
  
# re: 取反操作的细节问题 2011-04-08 14:46 | zuhd
@myjfm
嗯 我理解的补码的设计就是为了方便算术运算  回复  更多评论