📄 c语言中的位运算 - 嵌入式系统、软件、驱动 - 电子工程博客 - powered by supesite.htm
字号:
129 = 10000001<BR>A2A3.....An就是尾数位,不足23位后补0<BR>所以5.5 =
01000000101000000000000000000000 = 40A00000<BR>所以,对浮点数*2、/2只要对8位符号位+、-
即可,但不是左移、右移 <BR><BR>关于unsigned int 和 int
的在位运算上的不同,下面有个CU上的例子描述的很清楚:<BR><BR>[问题]:这个函数有什么问题吗?<BR><BR>/////////////////////////////////////////////////<BR>/**<BR>*
本函数将两个16比特位的值连结成为一个32比特位的值。<BR>* 参数:sHighBits 高16位<BR>* sLowBits 低16位<BR>*
返回:32位值<BR>**/<BR>long CatenateBits16(short sHighBits, short
sLowBits)<BR>{<BR>long lResult = 0; /* 32位值的临时变量*/<BR><BR>/*
将第一个16位值放入32位值的高16位 */<BR>lResult = sHighBits;<BR>lResult <<=
16;<BR><BR>/* 清除32位值的低16位 */<BR>lResult &= 0xFFFF0000;<BR><BR>/*
将第二个16位值放入32位值的低16位 */<BR>lResult |= (long)sLowBits;<BR><BR>return
lResult;<BR>}<BR>/////////////////////////////////////////////////<BR><BR><BR>[问题的发现]:<BR><BR>我们先看如下测试代码:<BR><BR>/////////////////////////////////////////////////<BR>int
main()<BR>{<BR>short sHighBits1 = 0x7fff;<BR>short sHighBits2 =
0x8f12;<BR>unsigned short usHighBits3 = 0xff12;<BR>short sLowBits1 =
0x7bcd; <BR>long lResult = 0;<BR><BR>printf("[sHighBits1 + sLowBits1]
";<BR><BR>lResult = CatenateBits16(sHighBits1,
sLowBits1);<BR>printf("lResult = %08x ", lResult, lResult);<BR><BR>lResult
= CatenateBits16(sHighBits2, sLowBits1);<BR>printf("lResult = %08x ",
lResult, lResult);<BR><BR>lResult = CatenateBits16(usHighBits3,
sLowBits1);<BR>printf("lResult = %08x ", lResult, lResult);
<BR>}<BR>/////////////////////////////////////////////////<BR><BR>运行结果为:<BR><BR>[sHighBits1
+ sLowBits1]<BR>lResult = 7fff7bcd<BR>lResult = 8f127bcd<BR>lResult =
ff127bcd<BR><BR>嗯,运行很正确嘛……于是我们就放心的在自己的程序中使用起这个函数来了。<BR><BR>可是忽然有一天,我们的一个程序无论如何结果都不对!经过n个小时的检查和调试,最后终于追踪到……CatenateBits16()
!?它的返回值居然是错的!!<BR><BR>“郁闷!”你说,“这个函数怎么会有问题呢!?”<BR><BR>可是,更郁闷的还在后头呢,因为你把程序中的输入量作为参数,在一个简单的main()里面单步调试:<BR><BR>/////////////////////////////////////////////////<BR>int
main()<BR>{<BR>short sHighBits1 = 0x7FFF;<BR>short sHighBits2 =
0x8F12;<BR>unsigned short usHighBits3 = 0x8F12;<BR><BR>short sLowBits1 =
0x7BCD; //你实际使用的参数<BR>short sLowBits2 = 0x8BCD; //你实际使用的参数<BR><BR>long
lResult = 0;<BR><BR>printf("[sHighBits1 + sLowBits1] ";<BR><BR>lResult =
CatenateBits16(sHighBits1, sLowBits1);<BR>printf("lResult = %08x ",
lResult, lResult);<BR><BR>lResult = CatenateBits16(sHighBits2,
sLowBits1);<BR>printf("lResult = %08x ", lResult, lResult);<BR><BR>lResult
= CatenateBits16(usHighBits3, sLowBits1);<BR>printf("lResult = %08x ",
lResult, lResult); <BR><BR>printf(" [sHighBits1 + sLowBits2]
";<BR><BR>lResult = CatenateBits16(sHighBits1,
sLowBits2);<BR>printf("lResult = %08x ", lResult, lResult);<BR><BR>lResult
= CatenateBits16(sHighBits2, sLowBits2);<BR>printf("lResult = %08x ",
lResult, lResult);<BR><BR>lResult = CatenateBits16(usHighBits3,
sLowBits2);<BR>printf("lResult = %08x ", lResult, lResult);<BR><BR>return
0;<BR>}<BR>/////////////////////////////////////////////////<BR><BR>发现结果竟然是:<BR><BR>[sHighBits1
+ sLowBits1]<BR>lResult = 7fff7bcd<BR>lResult = 8f127bcd<BR>lResult =
8f127bcd<BR><BR>[sHighBits1 + sLowBits2]<BR>lResult = ffff8bcd
//oops!<BR>lResult = ffff8bcd //oops!<BR>lResult = ffff8bcd
//oops!<BR><BR>前一次还好好的,后一次就ffff了?X档案?<BR><BR><BR>[X档案的真相]:<BR><BR>注意那两个我们用来当作低16位值的sLowBits1和sLowBits2。<BR><BR>已知:<BR>使用
sLowBits1 = 0x7bcd 时,函数返回正确的值;<BR>使用 sLowBits2 = 0x8bcd
时,函数中发生X档案。<BR><BR>那么,sLowBits1与sLowBits2有什么区别?<BR><BR>注意了,sLowBits1和sLowBits2都是short型(而不是unsigned
short),所以在这里,sLowBits1代表一个正数值,而sLowBits2却代表了一个负数值(因为8即是二进制1000,sLowBits2最高位是1)。<BR><BR>再看CatenateBits16()函数:<BR><BR>/////////////////////////////////////////////////<BR>long
CatenateBits16(short sHighBits, short sLowBits)<BR>{<BR>long lResult = 0;
/* 32位值的临时变量*/<BR><BR>/* 将第一个16位值放入32位值的高16位 */<BR>lResult =
sHighBits;<BR>lResult <<= 16;<BR><BR>/* 清除32位值的低16位 */<BR>lResult
&= 0xFFFF0000;<BR><BR>/* 将第二个16位值放入32位值的低16位 */<BR>lResult |=
(long)sLowBits; //注意这一句!!!!<BR><BR>return
lResult;<BR>}<BR>/////////////////////////////////////////////////<BR><BR>如果我们在函数中用<BR><BR>printf("sLowBits
= %04x ", sLowBits);<BR><BR>打印传入的sLowBits值,会发现<BR><BR>sLowBits = 0x7bcd
时,打印结果为<BR><BR>sLowBits = 7bcd<BR><BR>而sLowBits =
0x8bcd时,打印结果为<BR><BR>sLowBits =
ffff8bcd<BR><BR>是的,即使用%04x也打印出8位十六进制。<BR><BR>因此,我们看出来了:<BR><BR>当sLowBits =
0x8bcd时,函数中 "lResult |= (long)sLowBits;"
这一句执行,会先将sLowBits转换为<BR><BR>0xffff8bcd<BR><BR>再与lResult做或运算。由于现在lResult的值为
0xXXXX0000
(其中XXXX是任何值),所以显然,无论sHighBits是什么值,最后结果都会是<BR><BR>0xffff8bcd<BR><BR>而当sLowBits
= 0x7bcd时,函数中 "lResult |= (long)sLowBits;"
这一句执行,会先将sLowBits转换为<BR><BR>0x00007bcd<BR><BR>再与lResult做或运算。这样做或运算出来的结果当然就是对的。<BR><BR>也就是说,CatenateBits16()在sLowBits的最高位为0的时候表现正常,而在最高位为1的时候出现偏差。<BR><BR>[教训:在某些情况下作位运算和位处理的时候,考虑使用无符号数值——因为这个时候往往不需要处理符号。即使你需要的有符号的数值,那么也应该考虑自行在调用CatenateBits16()前后做转换——毕竟在位处理中,有符号数值相当诡异!]<BR><BR>下面这个CatenateBits16()版本应该会好一些:<BR><BR>/////////////////////////////////////////////////<BR>unsigned
long CatenateBits16(unsigned short sHighBits, unsigned short
sLowBits)<BR>{<BR>long lResult = 0;<BR><BR>/* 将第一个16位值放入32位值的高16位
*/<BR>lResult = sHighBits;<BR>lResult <<= 16;<BR><BR>/* 清除32位值的低16位
*/<BR>lResult &= 0xFFFF0000;<BR><BR>/* 将第二个16位值放入32位值的低16位
*/<BR>lResult |= (long)sLowBits & 0x0000FFFF;<BR><BR>return
lResult;<BR>}<BR>/////////////////////////////////////////////////<BR><BR>注意其中的
"lResult |= (long)sLowBits &
0x0000FFFF;"。事实上,现在即使我们把CatenateBits16()函数的参数(特别是sLowBits)声明为short,结果也会是对的。<BR><BR>如果有一天你把一只兔子扔给一只老虎,老虎把兔子吃了,第二天把一只老鼠扔给它,它又吃了,那么说明第一天你看错了:它本来就是一只猫。</FONT><BR><!-- 正文结束 --></P></TD></TR>
<TR>
<TD><BR>全文结束 </TD></TR></TBODY></TABLE></FONT><BR></DIV></DIV>
<DIV id=comment>
<H3><A href="http://bbs.ee365.cn/post.php?action=reply&tid=20716"
target=_blank>我也来说两句</A> <A style="MARGIN-RIGHT: 0.5em"
href="http://bbs.ee365.cn/viewthread.php?tid=20716" target=_blank>查看全部评论</A>
<STRONG>相关评论</STRONG> </H3>
<UL class=messagelist></UL>
<DIV class=pages>
<TABLE class=xspace-page summary="">
<TBODY>
<TR>
<TD><A href="http://bbs.ee365.cn/viewthread.php?tid=20716"
target=_blank>查看全部评论</A></TD>
<TD><A href="http://bbs.ee365.cn/post.php?action=reply&tid=20716"
target=_blank>我也来说两句</A></TD></TR></TBODY></TABLE></DIV></DIV></DIV></DIV>
<SCRIPT language=javascript type=text/javascript>
<!--
addImgLink("articlebody");
addImgLink("commentlist");
//-->
</SCRIPT>
<DIV class=sidebar>
<DIV id=hotthread>
<H3>近期热点主题</H3>
<UL>
<LI><A title=求助!!lwip移植后PING不通,请高手帮忙看一下,问题可能出在哪里?
href="http://space.ee365.cn/?action-viewthread-tid-28189"
target=_blank>求助!!lwip移植后PING不通,请高手帮忙看一下,问题可能出在哪里?</A> </LI>
<LI><A title=令人瞠目的USB比基尼泳装,太有创意了!
href="http://space.ee365.cn/?action-viewthread-tid-28174"
target=_blank>令人瞠目的USB比基尼泳装,太有创意了!</A> </LI>
<LI><A title="嵌入式操作系统uC/OS uClinux的比较"
href="http://space.ee365.cn/?action-viewthread-tid-28171"
target=_blank>嵌入式操作系统uC/OS uClinux的比较</A> </LI>
<LI><A title=IE浏览器的插件处理(原创)
href="http://space.ee365.cn/?action-viewthread-tid-28127"
target=_blank>IE浏览器的插件处理(原创)</A> </LI>
<LI><A title=RFID工作频率指南和典型应用
href="http://space.ee365.cn/?action-viewthread-tid-28173"
target=_blank>RFID工作频率指南和典型应用</A> </LI>
<LI><A title=工控软件的抗干扰设计
href="http://space.ee365.cn/?action-viewthread-tid-28176"
target=_blank>工控软件的抗干扰设计</A> </LI>
<LI><A title=请问lwIP的源码是在哪里下载的啊
href="http://space.ee365.cn/?action-viewthread-tid-28192"
target=_blank>请问lwIP的源码是在哪里下载的啊</A> </LI>
<LI><A title="RFID 测试技术分析"
href="http://space.ee365.cn/?action-viewthread-tid-28172" target=_blank>RFID
测试技术分析</A> </LI>
<LI><A title=“ST-Embest杯”颁奖大会暨Cortex技术研讨会(送iPOD)
href="http://space.ee365.cn/?action-viewthread-tid-28190"
target=_blank>“ST-Embest杯”颁奖大会暨Cortex技术研讨会(送iPOD)</A> </LI>
<LI><A title=有关遥控编码通讯控制的一些心得
href="http://space.ee365.cn/?action-viewthread-tid-28212"
target=_blank>有关遥控编码通讯控制的一些心得</A> <!--版块最新主题--></LI></UL></DIV>
<DIV id=newthreads>
<H3>最新主题</H3>
<UL>
<LI><A title=通广集团与河北省签定合同发展数字电视
href="http://space.ee365.cn/?action-viewthread-tid-28229"
target=_blank>通广集团与河北省签定合</A> </LI>
<LI><A title=您的论文发表了吗???
href="http://space.ee365.cn/?action-viewthread-tid-28228"
target=_blank>您的论文发表了吗???</A> </LI>
<LI><A title=请教关于sys_timeout()超时检测的问题
href="http://space.ee365.cn/?action-viewthread-tid-28223"
target=_blank>请教关于sys_timeout()超</A> </LI>
<LI><A title="[原创]国家级科技期刊 征集论文"
href="http://space.ee365.cn/?action-viewthread-tid-28217"
target=_blank>[原创]国家级科技期刊 </A></LI>
<LI><A title=有关遥控编码通讯控制的一些心得
href="http://space.ee365.cn/?action-viewthread-tid-28212"
target=_blank>有关遥控编码通讯控制的</A> </LI>
<LI><A title=请问lwIP的源码是在哪里下载的啊
href="http://space.ee365.cn/?action-viewthread-tid-28192"
target=_blank>请问lwIP的源码是在哪里</A> </LI>
<LI><A title=“ST-Embest杯”颁奖大会暨Cortex技术研讨会(送iPOD)
href="http://space.ee365.cn/?action-viewthread-tid-28190"
target=_blank>“ST-Embest杯”颁奖大会</A> </LI>
<LI><A title=求助!!lwip移植后PING不通,请高手帮忙看一下,问题可能出在哪里?
href="http://space.ee365.cn/?action-viewthread-tid-28189"
target=_blank>求助!!lwip移植后PING</A> </LI>
<LI><A title=工控软件的抗干扰设计
href="http://space.ee365.cn/?action-viewthread-tid-28176"
target=_blank>工控软件的抗干扰设计</A> </LI>
<LI><A title=令人瞠目的USB比基尼泳装,太有创意了!
href="http://space.ee365.cn/?action-viewthread-tid-28174"
target=_blank>令人瞠目的USB比基尼泳装</A> <!--论坛最新主题列表--></LI></UL></DIV></DIV>
<DIV class=hackbox></DIV></DIV><!-- Footer -->
<DIV id=footer>
<P><A href="http://space.ee365.cn/" target=_self>电子工程博客</A> | <A
href="http://space.ee365.cn/?action_site_type_panel" target=_self>快捷面板</A> | <A
href="http://space.ee365.cn/?action_site_type_map" target=_self>站点地图</A> | <A
href="http://space.ee365.cn/?action_site_type_link" target=_self>友情链接</A> | <A
href="mailto:gaofeng@ee365.cn" target=_self>联系我们</A></P>
<P>Powered by <A href="http://www.supesite.com/"
target=_blank><STRONG>SupeSite</STRONG></A> <EM>5.5</EM> © 2001-2006 <A
href="http://www.comsenz.com/" target=_blank>Comsenz Inc.</A> </P>
<P></P></DIV><!-- /Footer --></DIV></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -