一个C/C++中的移位操作问题
2010-08-04 14:17
253 查看
摘要:关于c/c++中由于CPU位宽造成的一个移位操作问题,b = ~a>>1中b的值的问题。
先看一段代码:
.codearea{ color:black; background-color:white; line-height:18px; border:1px solid #4f81bd; margin:0; width:auto !important; width:100%; overflow:auto; text-align:left; font-size:12px; font-family: "Courier New","Consolas","Fixedsys","BitStream Vera Sans Mono", courier,monospace,serif}
.codearea pre{ color:black; line-height:18px; padding:0 0 0 12px !important; margin:0em; background-color:#fff !important}
.linewrap pre{white-space:pre-wrap; white-space:-moz-pre-wrap; white-space:-pre-wrap; white-space:-o-pre-wrap; word-wrap:break-word; word-break:normal}
.codearea pre.alt{ background-color:#f7f7ff !important}
.codearea .lnum{color:#4f81bd;line-height:18px}
VC中运行的输出结果是:0xAA,原书中解释是运算符~的优先级小于>>(当然这是不可能滴,毫无疑问~优先于>>),但是最后的结果感觉确实是运算>>再做~操作的。但是我个人觉得应该是0x2A,于是又在TC下运行,结果果然是0x2A,与自己的计算结果相同。
为什么会有不同结果呢?于是我在其他多种编译器上运行了这段代码,比如:gcc,lcc,bcc等,结果都是0xAA,那么问题又在哪儿呢?
即使将程序代码修改为:
.codearea{ color:black; background-color:white; line-height:18px; border:1px solid #4f81bd; margin:0; width:auto !important; width:100%; overflow:auto; text-align:left; font-size:12px; font-family: "Courier New","Consolas","Fixedsys","BitStream Vera Sans Mono", courier,monospace,serif}
.codearea pre{ color:black; line-height:18px; padding:0 0 0 12px !important; margin:0em; background-color:#fff !important}
.linewrap pre{white-space:pre-wrap; white-space:-moz-pre-wrap; white-space:-pre-wrap; white-space:-o-pre-wrap; word-wrap:break-word; word-break:normal}
.codearea pre.alt{ background-color:#f7f7ff !important}
.codearea .lnum{color:#4f81bd;line-height:18px}
结果还是一样,说明确实是~运算符优先于>>。程序也是这样执行的。
最后我看了一下VC中的汇编代码:
.codearea{ color:black; background-color:white; line-height:18px; border:1px solid #4f81bd; margin:0; width:auto !important; width:100%; overflow:auto; text-align:left; font-size:12px; font-family: "Courier New","Consolas","Fixedsys","BitStream Vera Sans Mono", courier,monospace,serif}
.codearea pre{ color:black; line-height:18px; padding:0 0 0 12px !important; margin:0em; background-color:#fff !important}
.linewrap pre{white-space:pre-wrap; white-space:-moz-pre-wrap; white-space:-pre-wrap; white-space:-o-pre-wrap; word-wrap:break-word; word-break:normal}
.codearea pre.alt{ background-color:#f7f7ff !important}
.codearea .lnum{color:#4f81bd;line-height:18px}
终于弄懂了是怎么回事,在对a取反的时候先进行了一个自动的类型转换,转换结果为int型(从这里可以看出32位机CPU一次必须操作32个bit,不能只操作其中低8位),所以~a运算的结果就是0xFFFFFF55,那么对于有符号的数做右移操作实际上用的是SAR指令(不是SHR,两者的区别在后面说明),移位之后结果变为0xFFFFFFAA,然后在将其转换为unsigned char 类型赋值给变量b,那么b的值最后就是0xAA了。
那么为什么在TC上的结果会是0x2A了呢?那是因为TC中模拟的是8086体系的CPU结构(一个验证方法就是sizeof(int)==2),相当于运行于16bit位宽的计算机上,在这种结构中,CPU的寄存器位宽是16bit,但是有部分16bit寄存器可以分为两个8bit寄存器来独立操作,也就是说,在TC上运行时,~a操作不会进行类型转换,并且由于是unsigned char类型,结果就是0x55,然后直接对8位宽的0x55右移(采用SHR指令),结果就是0x2A了。
这个问题可以简化为:
.codearea{ color:black; background-color:white; line-height:18px; border:1px solid #4f81bd; margin:0; width:auto !important; width:100%; overflow:auto; text-align:left; font-size:12px; font-family: "Courier New","Consolas","Fixedsys","BitStream Vera Sans Mono", courier,monospace,serif}
.codearea pre{ color:black; line-height:18px; padding:0 0 0 12px !important; margin:0em; background-color:#fff !important}
.linewrap pre{white-space:pre-wrap; white-space:-moz-pre-wrap; white-space:-pre-wrap; white-space:-o-pre-wrap; word-wrap:break-word; word-break:normal}
.codearea pre.alt{ background-color:#f7f7ff !important}
.codearea .lnum{color:#4f81bd;line-height:18px}
可以使用Keil验证上述想法,在Keil C166中采用16为的CPU和Keil for Arm中采用32位的CPU结果与上述描述的一致。
[b]补充知识
先看一段代码:
1: #include <stdio.h>
2:
3:int main()
4: {
5: unsigned char a = 0xAA ;
6: unsigned char b = 0x00 ;
7: b = ~a>>1 ;
8: printf("0x%X",b) ;
9: return 0 ;
10: }
.codearea{ color:black; background-color:white; line-height:18px; border:1px solid #4f81bd; margin:0; width:auto !important; width:100%; overflow:auto; text-align:left; font-size:12px; font-family: "Courier New","Consolas","Fixedsys","BitStream Vera Sans Mono", courier,monospace,serif}
.codearea pre{ color:black; line-height:18px; padding:0 0 0 12px !important; margin:0em; background-color:#fff !important}
.linewrap pre{white-space:pre-wrap; white-space:-moz-pre-wrap; white-space:-pre-wrap; white-space:-o-pre-wrap; word-wrap:break-word; word-break:normal}
.codearea pre.alt{ background-color:#f7f7ff !important}
.codearea .lnum{color:#4f81bd;line-height:18px}
VC中运行的输出结果是:0xAA,原书中解释是运算符~的优先级小于>>(当然这是不可能滴,毫无疑问~优先于>>),但是最后的结果感觉确实是运算>>再做~操作的。但是我个人觉得应该是0x2A,于是又在TC下运行,结果果然是0x2A,与自己的计算结果相同。
为什么会有不同结果呢?于是我在其他多种编译器上运行了这段代码,比如:gcc,lcc,bcc等,结果都是0xAA,那么问题又在哪儿呢?
即使将程序代码修改为:
1: b = (~a)>>1 ;
.codearea{ color:black; background-color:white; line-height:18px; border:1px solid #4f81bd; margin:0; width:auto !important; width:100%; overflow:auto; text-align:left; font-size:12px; font-family: "Courier New","Consolas","Fixedsys","BitStream Vera Sans Mono", courier,monospace,serif}
.codearea pre{ color:black; line-height:18px; padding:0 0 0 12px !important; margin:0em; background-color:#fff !important}
.linewrap pre{white-space:pre-wrap; white-space:-moz-pre-wrap; white-space:-pre-wrap; white-space:-o-pre-wrap; word-wrap:break-word; word-break:normal}
.codearea pre.alt{ background-color:#f7f7ff !important}
.codearea .lnum{color:#4f81bd;line-height:18px}
结果还是一样,说明确实是~运算符优先于>>。程序也是这样执行的。
最后我看了一下VC中的汇编代码:
1: 0041339E mov byte ptr [a],0AAh
2: 004133A2 mov byte ptr ,0
3:
4: 004133A6 movzx eax,byte ptr [a]
5: 004133AA not eax
6: 004133AC sar eax,1
7: 004133AE mov byte ptr [b],al
.codearea{ color:black; background-color:white; line-height:18px; border:1px solid #4f81bd; margin:0; width:auto !important; width:100%; overflow:auto; text-align:left; font-size:12px; font-family: "Courier New","Consolas","Fixedsys","BitStream Vera Sans Mono", courier,monospace,serif}
.codearea pre{ color:black; line-height:18px; padding:0 0 0 12px !important; margin:0em; background-color:#fff !important}
.linewrap pre{white-space:pre-wrap; white-space:-moz-pre-wrap; white-space:-pre-wrap; white-space:-o-pre-wrap; word-wrap:break-word; word-break:normal}
.codearea pre.alt{ background-color:#f7f7ff !important}
.codearea .lnum{color:#4f81bd;line-height:18px}
终于弄懂了是怎么回事,在对a取反的时候先进行了一个自动的类型转换,转换结果为int型(从这里可以看出32位机CPU一次必须操作32个bit,不能只操作其中低8位),所以~a运算的结果就是0xFFFFFF55,那么对于有符号的数做右移操作实际上用的是SAR指令(不是SHR,两者的区别在后面说明),移位之后结果变为0xFFFFFFAA,然后在将其转换为unsigned char 类型赋值给变量b,那么b的值最后就是0xAA了。
那么为什么在TC上的结果会是0x2A了呢?那是因为TC中模拟的是8086体系的CPU结构(一个验证方法就是sizeof(int)==2),相当于运行于16bit位宽的计算机上,在这种结构中,CPU的寄存器位宽是16bit,但是有部分16bit寄存器可以分为两个8bit寄存器来独立操作,也就是说,在TC上运行时,~a操作不会进行类型转换,并且由于是unsigned char类型,结果就是0x55,然后直接对8位宽的0x55右移(采用SHR指令),结果就是0x2A了。
这个问题可以简化为:
1: unsigned int c = 0xFFAA;
2: int b ;
3:unsigned int d;
4: b = a>>1 ; /* 0xFFD5 */
5: d = c>>1 ; /* 0x7FD5 */
.codearea{ color:black; background-color:white; line-height:18px; border:1px solid #4f81bd; margin:0; width:auto !important; width:100%; overflow:auto; text-align:left; font-size:12px; font-family: "Courier New","Consolas","Fixedsys","BitStream Vera Sans Mono", courier,monospace,serif}
.codearea pre{ color:black; line-height:18px; padding:0 0 0 12px !important; margin:0em; background-color:#fff !important}
.linewrap pre{white-space:pre-wrap; white-space:-moz-pre-wrap; white-space:-pre-wrap; white-space:-o-pre-wrap; word-wrap:break-word; word-break:normal}
.codearea pre.alt{ background-color:#f7f7ff !important}
.codearea .lnum{color:#4f81bd;line-height:18px}
可以使用Keil验证上述想法,在Keil C166中采用16为的CPU和Keil for Arm中采用32位的CPU结果与上述描述的一致。
[b]补充知识
;SHR(Shift Right): 逻辑右移 最高位移动至次高位,然后最高位补零 ;SAR(Shift Arithmetic Right): 算术右移 这种情况下,最高位是符号位,最高位移动至次高位,最高位保持不变
相关文章推荐
- C/C++中的一个巨大的坑:移位操作的优先级问题
- 有关C++参数传值的一个问题探讨
- C和C++的内存操作小贴士(一):const char*的内存释放问题
- Eclipse 在 Mac OS X 上调试 c/c++ 的一个问题
- 我创建了一个托盘图标,可以正常使用,点击右键打开菜单。问题是如果点击右键后不选择其中一个菜单项进行操作的话,它就总不消失。
- zz一个VS2005无法调试C++的问题
- (编程题目)约瑟夫问题(实用C++编出一个程序解决约瑟夫问题)--凌风
- 使用eclipse for c++的一个报错问题
- 黑马程序员——java中两个线程对同一个数据做不同操作的安全问题
- ASP“操作必须使用一个可更新的查询”问题的解决办法
- C++ 操作Excel问题
- 初学lua --lua嵌入c++的一个问题(初始化lua出错,版本问题)
- android操作Bitmap的一个小问题
- 高并发操作同一个数据造成错误逻辑数据问题
- thinking in c++ 读书笔记---友元函数的一个问题
- Win32 C++工程中使用离屏面碰到的一个奇怪问题
- MFC 在一个项目中添加log文件的读写操作问题
- C++中文件操作EOF的问题
- C++调用Android函数弹出一个提示框中出现的问题总结
- C/C++学习笔记32:字符串操作与字符子串问题