工作中与处理器有关的问题总结

<p><!-- [if !mso]>
<style>
v/:* {behavior:url(#default#VML);}
o/:* {behavior:url(#default#VML);}
p/:* {behavior:url(#default#VML);}
.shape {behavior:url(#default#VML);}
v/:textbox {display:none;}
</style>
<![endif]--><!-- [if !ppt]--><!-- [endif]-->
</p>
<div class="O">
<div>
<span style="font-size: medium;"><span style="">经常遇到的典型问题或者说我能想到的有以下这些:
</span>
</span>
</div>
<div>
<span style="font-size: medium;"><span style="font-family: Calibri;"><span style="">Ø</span>
</span>
<span style="">字节序
</span>
</span>
</div>
<div>
<span style="font-size: medium;"><span style="font-family: Calibri;"><span style="">Ø</span>
</span>
<span style="">字节对齐
</span>
</span>
</div>
<div>
<span style="font-size: medium;"><span style="font-family: Calibri;"><span style="">Ø</span>
</span>
<span style="">异常
</span>
</span>
</div>
<div>
<span style="font-size: medium;"><span style="font-family: Calibri;"><span style="">Ø</span>
</span>
<span style="">符号位问题
</span>
</span>
</div>
<div>
<span style="font-size: medium;"><span style="font-family: Calibri;"><span style="">Ø</span>
</span>
<span style="">堆栈溢出
</span>
</span>
</div>
<div>
<span style="font-size: medium;"><span style="font-family: Calibri;"><span style="">Ø</span>
</span>
<span style="">空指针
</span>
</span>
</div>
<span style="font-size: medium;">
</span>
<div>
<span style="font-size: medium;"><span style="font-family: Calibri;"><span style="">Ø</span>
</span>
<span style="">编译</span>
<span style="font-family: Calibri;" lang="EN-US">&</span>
<span style="">反汇编</span>
</span>
</div>
<div>
<span style="font-size: medium;"><br></span>
</div>
<div>
<!-- [if !mso]>
<style>
v/:* {behavior:url(#default#VML);}
o/:* {behavior:url(#default#VML);}
p/:* {behavior:url(#default#VML);}
.shape {behavior:url(#default#VML);}
v/:textbox {display:none;}
</style>
<![endif]--><!-- [if !ppt]--><!-- [endif]-->
<div class="O">
<div>
<span style="font-size: medium;"><span style="">字节序问题:</span>
<span style=""><strong><a href="http://www.cnblogs.com/wqlblogger/archive/2008/01/25/1052915.html" target="_parent">大端法小端法</a>
</strong>
</span>
<span style="" lang="EN-US"><strong>
</strong>
</span>
</span>
</div>
<div>
<span style="font-size: medium;"><span style="font-family: Calibri;" lang="EN-US"><strong><span style="width: 8.71%;"> </span>
</strong>
</span>
<span style="">其实说白了就是一个顺序问题。现代的计算机系统</span>
<span style="">一般采用</span>
<span style=""><strong>字节</strong>
</span>
<span style="font-family: Calibri;" lang="EN-US">(Octet, 8 bit Byte)</span>
<span style="">作为逻辑寻址单位。</span>
<span style="">当物理单位的长度大于</span>
<span style="font-family: Calibri;" lang="EN-US">1</span>
<span style="">个字节时,就要区分</span>
<span style=""><strong>字节顺序</strong>
</span>
<span style=""><strong>。</strong>
</span>
<span style="">常见的字节顺序有两种:</span>
<span style="font-family: Calibri;" lang="EN-US"><strong>Big Endian</strong>
</span>
<span style="">和</span>
<span style="font-family: Calibri;" lang="EN-US"><strong>Little </strong>
</span>
<span style="font-family: Calibri;" lang="EN-US"><strong>Endian.</strong>
</span>
<span style="font-family: Calibri;" lang="EN-US"> Intel X86</span>
<span style="">平台采用</span>
<span style="font-family: Calibri; color: red;" lang="EN-US">Little Endian</span>
<span style="">,而</span>
<span style="font-family: Calibri;" lang="EN-US">PowerPC</span>
<span style="">、</span>
<span style="font-family: Calibri;" lang="EN-US">ARM</span>
<span style="">、</span>
<span style="font-family: Calibri;" lang="EN-US">MIPS</span>
<span style="">处理器则采用了</span>
<span style="font-family: Calibri; color: red;" lang="EN-US">Big Endian</span>
<span style="">
</span>
</span>
</div>
<span style="font-size: medium;">
</span>
<div>
<span style="font-size: medium;"><span style="font-family: Calibri;"> </span>
<span style="">于是问题来了,一个两字节的数</span>
<span style="font-family: Calibri;" lang="EN-US">0XABCD</span>
<span style="">,要存</span>
<span style="">储在</span>
<span style="font-family: Calibri;" lang="EN-US">0-1</span>
<span style="">这两个字节中,那么</span>
<span style="font-family: Calibri;" lang="EN-US">0</span>
<span style="">中是存</span>
<span style="font-family: Calibri;" lang="EN-US">AB</span>
<span style="">还是</span>
<span style="font-family: Calibri;" lang="EN-US">CD</span>
<span style="">,</span>
<span style="font-family: Calibri;" lang="EN-US">PPC</span>
<span style="">、</span>
<span style="font-family: Calibri;" lang="EN-US">ARM</span>
<span style="">和</span>
<span style="font-family: Calibri;" lang="EN-US">MIPS</span>
<span style="">等选择了</span>
<span style="font-family: Calibri;" lang="EN-US">AB</span>
<span style="">,</span>
<span style="font-family: Calibri;" lang="EN-US">X86</span>
<span style="">选择了</span>
<span style="font-family: Calibri;" lang="EN-US">CD.
</span>
</span>
</div>
<div>
<!-- [if !mso]>
<style>
v/:* {behavior:url(#default#VML);}
o/:* {behavior:url(#default#VML);}
p/:* {behavior:url(#default#VML);}
.shape {behavior:url(#default#VML);}
v/:textbox {display:none;}
</style>
<![endif]--><!-- [if !ppt]--><!-- [endif]-->
<div class="O">
<div>
<span style="font-size: medium;"><span style="font-family: Calibri;"> </span>
<span style="">说到字节序,一定要区分主机序和网络序。
</span>
</span>
</div>
<div>
<span style="font-size: medium;"><span style="font-family: Calibri;" lang="EN-US"><span style="width: 9.47%;"> </span>
</span>
<span style="">网络序:</span>
<span style="font-family: Calibri;" lang="EN-US">TCP/IP</span>
<span style="">各层协议将字节序定义为</span>
<span style="font-family: Calibri;" lang="EN-US">Big-</span>
<span style="font-family: Calibri;" lang="EN-US">Endian</span>
<span style="">,因此</span>
<span style="font-family: Calibri;" lang="EN-US">TCP/IP</span>
<span style="">协议中使用的字节序通常称之为</span>
<span style="">网络字节序。
</span>
</span>
</div>
<span style="font-size: medium;">
</span>
<div>
<span style="font-size: medium;"><span style="font-family: Calibri;" lang="EN-US"><span style="width: 8.86%;"> </span>
</span>
<span style="">主机序:它遵循</span>
<span style="font-family: Calibri;" lang="EN-US">Little-Endian</span>
<span style="">规则。所以当两台主</span>
<span style="">机之间要通过</span>
<span style="font-family: Calibri;" lang="EN-US">TCP/IP</span>
<span style="">协议进行通信的时候就需要调用</span>
<span style="">相应的函数进行主机序(</span>
<span style="font-family: Calibri;" lang="EN-US">Little-Endian</span>
<span style="">)和网络序(</span>
<span style="font-family: Calibri;" lang="EN-US">Big-Endian</span>
<span style="">)的转换。</span>
</span>
</div>
<div>
<span style="font-size: medium;"><br></span>
</div>
<!-- [if !mso]>
<style>
v/:* {behavior:url(#default#VML);}
o/:* {behavior:url(#default#VML);}
p/:* {behavior:url(#default#VML);}
.shape {behavior:url(#default#VML);}
v/:textbox {display:none;}
</style>
<![endif]--><!-- [if !ppt]--><!-- [endif]--><span style="font-size: medium;">
</span>
<div class="O">
<div>
<span style="font-size: medium;"><span style="">编程规范里面提到过数据结构设计需要考虑字节对齐。
</span>
</span>
</div>
<span style="font-size: medium;">
</span>
<div>
<span style="font-size: medium;"><span style="font-family: Calibri;"> </span>
<span style="">所谓字节对齐,就是要求某个数据在内存中的起</span>
<span style="">始位置必须是该数据类型的</span>
<span style="">对齐大小</span>
<span style="">的整数倍。基本</span>
<span style="">数据类型(</span>
<span style="font-family: Calibri;">char</span>
<span style="">,</span>
<span style="font-family: Calibri;">int</span>
<span style="">,</span>
<span style="font-family: Calibri;">long</span>
<span style="">等)的对齐大小等同于类</span>
<span style="">型的大小,结构体的对齐大小等同于其各成员变量的</span>
<span style="">对齐大小的最大值,数组的对齐大小等于其基本类型</span>
<span style="">的对齐大小。数据的大小必须是对齐大小的整数倍。</span>
</span>
</div>
<div>
<!-- [if !mso]>
<style>
v/:* {behavior:url(#default#VML);}
o/:* {behavior:url(#default#VML);}
p/:* {behavior:url(#default#VML);}
.shape {behavior:url(#default#VML);}
v/:textbox {display:none;}
</style>
<![endif]--><!-- [if !ppt]--><!-- [endif]-->
<div class="O">
<div>
<span style="font-size: medium;"><span style="">为什么要字节对齐?
</span>
</span>
</div>
<div>
<span style="font-size: medium;"><span style="font-family: Calibri;"> </span>
<span style="">因为某些处理器不允许</span>
<span style="font-family: Calibri;" lang="EN-US">16</span>
<span style="">位和</span>
<span style="font-family: Calibri;" lang="EN-US">32</span>
<span style="">位的数据在内存</span>
<span style="">中任意排放。
</span>
</span>
</div>
<span style="font-size: medium;">
</span>
<div>
<span style="font-size: medium;"><span style="font-family: Calibri;" lang="EN-US"><span style="width: 9.03%;"> </span>
</span>
<span style="">通常</span>
<span style="font-family: Calibri;" lang="EN-US">32</span>
<span style="">位的处理器通过总线访问(包括读和写)</span>
<span style="">内存数据。每个总线访问周期可以访问</span>
<span style="font-family: Calibri;" lang="EN-US">32</span>
<span style="">位内存数据</span>
<span style="">。内存数据是以</span>
<span style="font-family: Calibri;" lang="EN-US">8</span>
<span style="">位的字节为单位存放的。假如一个</span>
<span style="font-family: Calibri;" lang="EN-US">32</span>
<span style="">位的数据没有在</span>
<span style="font-family: Calibri;" lang="EN-US">4</span>
<span style="">字节整除的内存地址处存放,那么处</span>
<span style="">理器就需要</span>
<span style="font-family: Calibri;" lang="EN-US">2</span>
<span style="">个总线周期对其进行访问。通过合理的内</span>
<span style="">存对齐可以提高访问效率。</span>
</span>
</div>
<div>
<!-- [if !mso]>
<style>
v/:* {behavior:url(#default#VML);}
o/:* {behavior:url(#default#VML);}
p/:* {behavior:url(#default#VML);}
.shape {behavior:url(#default#VML);}
v/:textbox {display:none;}
</style>
<![endif]--><!-- [if !ppt]--><!-- [endif]-->
<div class="O">
<div>
<span style="font-size: medium;"><span style="">为什么要字节对齐?(续一)
</span>
</span>
</div>
<div>
<span style="font-size: medium;"><span style="font-family: Calibri;"> </span>
<span style="">访存是通过特定的指令完成的,为了减少访存的</span>
<span style="">时间,大部分</span>
<span style="font-family: Calibri;">CPU</span>
<span style="">都有一次可以读写</span>
<span style="font-family: Calibri;">N</span>
<span style="">个字节(</span>
<span style="font-family: Calibri;">N</span>
<span style="">取决</span>
<span style="">于位宽)的指令,但是由于硬件上的限制,这些指令</span>
<span style="">都是有限制的,比如地址必须是</span>
<span style="font-family: Calibri;">N</span>
<span style="">的整数倍(原因没</span>
<span style="">查到)。
</span>
</span>
</div>
<span style="font-size: medium;">
</span>
<div>
<span style="font-size: medium;"><span style="font-family: Calibri;"> </span>
<span style="">在不对齐的情况下,有些处理器会通过组合指令</span>
<span style="">的方式达到目标。比如需要从地址</span>
<span style="font-family: Calibri;" lang="EN-US">1</span>
<span style="">处取一个</span>
<span style="font-family: Calibri;" lang="EN-US">unsigned </span>
<span style="font-family: Calibri;" lang="EN-US">int</span>
<span style="">类型数据,可以先从</span>
<span style="font-family: Calibri;" lang="EN-US">0</span>
<span style="">处取</span>
<span style="font-family: Calibri;" lang="EN-US">4</span>
<span style="">字节,然后从</span>
<span style="font-family: Calibri;" lang="EN-US">4</span>
<span style="">处取</span>
<span style="font-family: Calibri;" lang="EN-US">4</span>
<span style="">字</span>
<span style="">节,再进行移位相或获得需要的数。如果是一个</span>
<span style="font-family: Calibri;" lang="EN-US">int</span>
<span style="">类</span>
<span style="">型,则更加麻烦,因为移位的时候需要处理符号位,</span>
<span style="">对效率会有很大影响。</span>
</span>
</div>
<div>
<!-- [if !mso]>
<style>
v/:* {behavior:url(#default#VML);}
o/:* {behavior:url(#default#VML);}
p/:* {behavior:url(#default#VML);}
.shape {behavior:url(#default#VML);}
v/:textbox {display:none;}
</style>
<![endif]--><!-- [if !ppt]--><!-- [endif]-->
<div class="O">
<div>
<span style="font-size: medium;"><span style="">为什么要字节对齐?(续二)
</span>
</span>
</div>
<div>
<span style="font-size: medium;"><span style="font-family: Calibri;"> </span>
<span style="font-family: Calibri; color: red;" lang="EN-US">mips</span>
<span style="">是定长指令的设计,每条指令都是</span>
<span style="font-family: Calibri;" lang="EN-US">32</span>
<span style="">比特(</span>
<span style="">或许会有</span>
<span style="font-family: Calibri;" lang="EN-US">64</span>
<span style="">的出现?)。
</span>
</span>
</div>
<div>
<span style="font-size: medium;"><span style="font-family: Calibri;"> 32</span>
<span style="">位的指令长度也就意味着要传递一个</span>
<span style="font-family: Calibri;" lang="EN-US">32</span>
<span style="">位的地</span>
<span style="">址起码需要两条指令(指令有若干位是操作码)。因</span>
<span style="">此如果在</span>
<span style="font-family: Calibri;" lang="EN-US">mips</span>
<span style="">中如果需要实现不对齐的内存访问,需</span>
<span style="">要耗费更多的时间。于是</span>
<span style="font-family: Calibri;" lang="EN-US">mips</span>
<span style="">干脆直接不处理这种情</span>
<span style="">况,遇到不对齐的直接</span>
<span style="font-family: Calibri;" lang="EN-US">error</span>
<span style="">。
</span>
</span>
</div>
<span style="font-size: medium;">
</span>
<div>
<span style="font-size: medium;"><span style="font-family: Calibri;" lang="EN-US"><span style="width: 8.71%;"> </span>
</span>
<span style="">无论如何,为了提高程序的性能,数据结构(尤其</span>
<span style="">是栈)应该尽可能地在自然边界上对齐。原因在于,</span>
<span style="">为了访问未对齐的内存,处理器需要作两次内存访问</span>
<span style="">;</span>
</span>
</div>
<div>
<!-- [if !mso]>
<style>
v/:* {behavior:url(#default#VML);}
o/:* {behavior:url(#default#VML);}
p/:* {behavior:url(#default#VML);}
.shape {behavior:url(#default#VML);}
v/:textbox {display:none;}
</style>
<![endif]--><!-- [if !ppt]--><!-- [endif]-->
<div class="O">
<div>
<span style="font-size: medium;"><span style="">然而,对齐的内存访问仅需要一次访问。
</span>
</span>
</div>
<div>
<span style="font-size: medium;"><span style="font-family: Calibri;" lang="EN-US"><span style="width: 8.86%;"> </span>
</span>
<span style="">一个字或双字操作数跨越了</span>
<span style="font-family: Calibri;" lang="EN-US">4</span>
<span style="">字节边界,或者一个</span>
<span style="">四字操作数跨越了</span>
<span style="font-family: Calibri;" lang="EN-US">8</span>
<span style="">字节边界,被认为是未对齐的,从</span>
<span style="">而需要两次总线周期来访问内存。一个字起始地址是</span>
<span style="">奇数但却没有跨越字边界被认为是对齐的,能够在一</span>
<span style="">个总线周期中被访问。
</span>
</span>
</div>
<span style="font-size: medium;">
</span>
<div>
<span style="font-size: medium;"><span style="font-family: Calibri;" lang="EN-US"><span style="width: 8.89%;"> </span>
</span>
<span style="">编译器对内存对齐的处理:</span>
<span style="font-family: Calibri;" lang="EN-US">c</span>
<span style="">编译器默认将结构、</span>
<span style="">栈中的成员数据进行内存对齐。编译器将未对齐的成</span>
<span style="">员向后移,将每一个都成员对齐到自然边界上,从而</span>
<span style="">也导致了整个结构的尺寸变大。</span>
</span>
</div>
<div>
<!-- [if !mso]>
<style>
v/:* {behavior:url(#default#VML);}
o/:* {behavior:url(#default#VML);}
p/:* {behavior:url(#default#VML);}
.shape {behavior:url(#default#VML);}
v/:textbox {display:none;}
</style>
<![endif]--><!-- [if !ppt]--><!-- [endif]--><span style="font-size: medium;">
</span>
<div class="O">
<span style="font-size: medium;"><span style="font-family: Calibri;" lang="EN-US"><span style="width: 2.54%;"> </span>
</span>
<span style="">字节对齐的细节和编译器实现相关,但一般而言,满足三个准则:<br></span>
<span style="font-family: Calibri; color: red;" lang="EN-US">1) </span>
<span style="">结构体变量的首地址能够被其最宽基本类型成员的大小所整除;<br></span>
<span style="font-family: Calibri; color: red;" lang="EN-US">2) </span>
<span style="">结构体每个成员相对于结构体首地址的偏移量(</span>
<span style="font-family: Calibri;" lang="EN-US">offset</span>
<span style="">)都是成员大小的整数倍,<br></span>
<span style="">如有需要编译器会在成员之间加上填充字节(</span>
<span style="font-family: Calibri;" lang="EN-US">internal adding</span>
<span style="">);<br></span>
<span style="font-family: Calibri; color: red;" lang="EN-US">3) </span>
<span style="">结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最<br></span>
<span style="">末一个成员之后加上填充字节(</span>
<span style="font-family: Calibri;" lang="EN-US">trailing padding</span>
<span style="">)</span>
</span>
</div>
<div class="O">
<span style="font-size: medium;"><br></span>
</div>
<div class="O">
<!-- [if !mso]>
<style>
v/:* {behavior:url(#default#VML);}
o/:* {behavior:url(#default#VML);}
p/:* {behavior:url(#default#VML);}
.shape {behavior:url(#default#VML);}
v/:textbox {display:none;}
</style>
<![endif]--><!-- [if !ppt]--><!-- [endif]-->
<div class="O">
<div>
<span style="font-size: medium;"><span style="font-family: Calibri;"> </span>
<span style="">不同的</span>
<span style="font-family: Calibri;" lang="EN-US">CPU</span>
<span style="">对异常的定义是不一样的,比如这段代码:</span>
<span style="font-family: Calibri;" lang="EN-US">int </span>
<span style="font-family: Calibri;" lang="EN-US">*piTest = (int*)3; *piTest = 1;</span>
<span style="">这段代码</span>
<span style="font-family: Calibri;" lang="EN-US">PPC</span>
<span style="">能正常处理,</span>
<span style="font-family: Calibri;" lang="EN-US">MIPS</span>
<span style="">则会抛出异常。另外还有一些修改</span>
<span style="font-family: Calibri;" lang="EN-US">data</span>
<span style="">段的操作,在</span>
<span style="font-family: Calibri;" lang="EN-US">PPC</span>
<span style="">上是</span>
<span style="">没问题的,</span>
<span style="font-family: Calibri;" lang="EN-US">X86</span>
<span style="">上会异常。
</span>
</span>
</div>
<div>
<span style="font-size: medium;"><span style="font-family: Calibri;"> </span>
<span style="">异常一般通过中断处理,当</span>
<span style="font-family: Calibri;" lang="EN-US">CPU</span>
<span style="">断定产生了异常的时候,</span>
<span style="">会产生一个中断,然后跳转到相应的中断向量去执行中断处理</span>
<span style="">。。
</span>
</span>
</div>
<span style="font-size: medium;">
</span>
<div>
<span style="font-size: medium;"><span style="font-family: Calibri;"> </span>
<span style="">不同的</span>
<span style="font-family: Calibri;" lang="EN-US">CPU</span>
<span style="">对异常的定义不一样,编码怎么办?按照最严</span>
<span style="">格的那个来。比如字节对齐,看起来较真了一点,但是这个在</span>
<span style="">那些容忍不对齐的设备上也是有好处的,可以提高效率。而修</span>
<span style="">改</span>
<span style="font-family: Calibri;" lang="EN-US">data</span>
<span style="">段,本身就是一个不符合常理的操作。
</span>
</span>
</div>
<div>
<span style="font-size: medium;"><br></span>
</div>
<div>
<!-- [if !mso]>
<style>
v/:* {behavior:url(#default#VML);}
o/:* {behavior:url(#default#VML);}
p/:* {behavior:url(#default#VML);}
.shape {behavior:url(#default#VML);}
v/:textbox {display:none;}
</style>
<![endif]--><!-- [if !ppt]--><!-- [endif]-->
<div class="O">
<div>
<span style="font-size: medium;"><span style="font-family: Calibri;" lang="EN-US"><span style="width: 3.32%;"> </span>
</span>
<span style="">符号位的问题可以肯定的是这个和</span>
<span style="font-family: Calibri;" lang="EN-US">mips</span>
<span style="">的一个很重要</span>
<span style="">的特性有关:</span>
<span style="font-family: Calibri;" lang="EN-US">mips</span>
<span style="">只能处理</span>
<span style="font-family: Calibri;" lang="EN-US">32</span>
<span style="">位的数据。也即如果对</span>
<span style="">两个</span>
<span style="font-family: Calibri;" lang="EN-US">char</span>
<span style="">相加,</span>
<span style="font-family: Calibri;" lang="EN-US">mips</span>
<span style="">需要把两个</span>
<span style="font-family: Calibri;" lang="EN-US">char</span>
<span style="">填充成两个</span>
<span style="font-family: Calibri;" lang="EN-US">32</span>
<span style="">位</span>
<span style="">的数,并对符号位进行处理,以保存溢出等特性,然</span>
<span style="">后再相加。
</span>
</span>
</div>
<span style="font-size: medium;">
</span>
<div>
<span style="font-size: medium;"><span style="font-family: Calibri;"> </span>
<span style="">这个也要求大家在定义数据的时候,需要考虑好</span>
<span style="">,这个数据的特性,是有符号的还是无符号的
</span>
</span>
</div>
<div>
<span style="font-size: medium;"><br></span>
</div>
<div>
<!-- [if !mso]>
<style>
v/:* {behavior:url(#default#VML);}
o/:* {behavior:url(#default#VML);}
p/:* {behavior:url(#default#VML);}
.shape {behavior:url(#default#VML);}
v/:textbox {display:none;}
</style>
<![endif]--><!-- [if !ppt]--><!-- [endif]-->
<div class="O">
<div>
<span style="font-size: medium;"><span style="font-family: Calibri;" lang="EN-US"><span style="width: 3.34%;"> </span>
</span>
<span style="">从物理上讲,堆栈就是一段连续分配的内存空间。在</span>
<span style="">一个程序中,会声明各种变量。静态全局变量是位于</span>
<span style="">数据段并且在程序开始运行的时候被加载。而程序的</span>
<span style="">动态的局部变量则分配在堆栈里面。
</span>
</span>
</div>
<div>
<span style="font-size: medium;"><span style="font-family: Calibri;" lang="EN-US"><span style="width: 8.71%;"> </span>
</span>
<span style="">堆栈溢出就是不顾堆栈中分配的局部数据块大小,</span>
<span style="">向该数据块写入了过多的数据,导致数据越界。结果</span>
<span style="">覆盖了老的堆栈数据。</span>
<span style="font-family: Calibri;">
</span>
</span>
</div>
<div>
<span style="font-size: medium;"><span style="font-family: Calibri;" lang="EN-US"><span style="width: 8.71%;"> </span>
</span>
<span style="">有两种情况会引起堆栈溢出,第一种可能出现的情</span>
<span style="">况是如果你定义了大数组会导致堆栈溢出;第二种因</span>
<span style="">为函数的参数和里面声明的局部变量,</span>
</span>
<!-- [if !mso]>
<style>
v/:* {behavior:url(#default#VML);}
o/:* {behavior:url(#default#VML);}
p/:* {behavior:url(#default#VML);}
.shape {behavior:url(#default#VML);}
v/:textbox {display:none;}
</style>
<![endif]--><!-- [if !ppt]--><!-- [endif]-->
<div class="O">
<span style="font-size: medium;">
</span>
<div>
<span style="font-size: medium;"><span style="">都是在栈内分配空间。所以如果递归调用层次过</span>
<span style="">深的话,就有可能栈溢出。不要在递归函数内</span>
<span style="">申请大的空间。</span>
</span>
</div>
<div>
<!-- [if !mso]>
<style>
v/:* {behavior:url(#default#VML);}
o/:* {behavior:url(#default#VML);}
p/:* {behavior:url(#default#VML);}
.shape {behavior:url(#default#VML);}
v/:textbox {display:none;}
</style>
<![endif]--><!-- [if !ppt]--><!-- [endif]-->
<div class="O">
<div>
<span style="font-size: medium;"><span style="font-family: Calibri;"> </span>
<span style="">这个章节一般不会用到,但是如果能理解对提高问题处理能力还是有帮</span>
<span style="">助的。这个是编译模拟器的</span>
<span style="font-family: Calibri;" lang="EN-US">.a</span>
<span style="">时的截图:
</span>
</span>
</div>
<div>
<span style="font-size: medium;"><span style="font-family: Calibri;">
</span>
</span>
</div>
<div>
<span style="font-size: medium;"><span style="">
</span>
</span>
</div>
<div>
<span style="font-size: medium;"><span style="font-family: Calibri;"> </span>
<span style="">红色部分大家应该能注意到这个名称包含了一个</span>
<span style="font-family: Calibri;">“</span>
<span style="font-family: Calibri;" lang="EN-US">pentium</span>
<span style="font-family: Calibri;">”</span>
<span style="">,实际就是</span>
<span style="">奔腾处理器的名称。从这个可以看出,编译器是直接和处理器相关的,不同</span>
<span style="">的处理器会有不同的编译器。不知道谁看过《疯狂的程序员》,里面就提到</span>
<span style="">一个汇编的问题,说懂得汇编的人有个好处,不用等那些最新的</span>
<span style="font-family: Calibri;" lang="EN-US">CPU</span>
<span style="">的编译</span>
<span style="">器,因为厂商推出一款新的架构的处理器的时候,有可能会先推出汇编编译</span>
<span style="">程序,其他语言的编译器可能需要过一阵子才能发布。之所以这样是因为不</span>
<span style="">同的</span>
<span style="font-family: Calibri;" lang="EN-US">CPU</span>
<span style="">的指令集是不一样的,而汇编基本是和指令集挂钩的,因为汇编解</span>
<span style="">析程序实现比较容易,而像</span>
<span style="font-family: Calibri;" lang="EN-US">C</span>
<span style="">这种高级语言的解析则费劲的多。
</span>
</span>
</div>
<span style="font-size: medium;">
</span>
<div>
<span style="font-size: medium;"><span style="font-family: Calibri;"> </span>
<span style="">编译中大部分的错误提示都是语言性质的提示,处理器性质的提示很少</span>
<span style="">。</span>
</span>
</div>
<div>
<!-- [if !mso]>
<style>
v/:* {behavior:url(#default#VML);}
o/:* {behavior:url(#default#VML);}
p/:* {behavior:url(#default#VML);}
.shape {behavior:url(#default#VML);}
v/:textbox {display:none;}
</style>
<![endif]--><!-- [if !ppt]--><!-- [endif]-->
<div class="O">
<div>
<span style="font-size: medium;"><span style="font-family: Calibri;"> </span>
<span style="">编译过程我们不用太多关注处理器的信息,那是编译器的</span>
<span style="">任务。但是反汇编的时候,如果需要理解反汇编出来的代码,</span>
<span style="">则必须要理解相关处理器的指令集。我认为应该多少学习一下</span>
<span style="">汇编代码。
</span>
</span>
</div>
<span style="font-size: medium;">
</span>
<div>
<span style="font-size: medium;"><span style="font-family: Calibri;"> </span>
<span style="">而我们为什么要会反汇编。我在</span>
<span style="font-family: Calibri;" lang="EN-US">2126EA-MA(B)</span>
<span style="">这款</span>
<span style="font-family: Calibri;" lang="EN-US">MIPS</span>
<span style="">芯片的设备中深刻体会了一把,也吃到了不少甜头。个人觉得</span>
<span style="">反汇编有两个作用:</span>
<span style="font-family: Calibri;" lang="EN-US">1</span>
<span style="">、</span>
<span style="font-family: Calibri;" lang="EN-US">debug</span>
<span style="">。有些看代码很难找的</span>
<span style="font-family: Calibri;" lang="EN-US">bug</span>
<span style="">在反</span>
<span style="">汇编下很容易</span>
<span style="font-family: Calibri;">“</span>
<span style="">原形毕露</span>
<span style="font-family: Calibri;">”</span>
<span style="">。</span>
<span style="font-family: Calibri;" lang="EN-US">2</span>
<span style="">、更好的理解你的代码。反汇编出</span>
<span style="">来的东西更接近指令,对比阅读能让你更好的理解同一个功能</span>
<span style="">,用不同的代码写会有什么不同的指令体现,什么方式效率更</span>
<span style="">高。这也是我上面提到的大家最好抽空学学汇编语言,有助于</span>
<span style="">理解代码,更好更快的定位问题。</span>
</span>
</div>
<div>
<span style="font-size: medium;"><br></span>
</div>
<div>
<!-- [if !mso]>
<style>
v/:* {behavior:url(#default#VML);}
o/:* {behavior:url(#default#VML);}
p/:* {behavior:url(#default#VML);}
.shape {behavior:url(#default#VML);}
v/:textbox {display:none;}
</style>
<![endif]--><!-- [if !ppt]--><!-- [endif]-->
<div class="O">
<div>
<span style="font-size: medium;"><span style="">以下是个人的一些对处理器、编译器的理解后总结的编</span>
<span style="">程习惯:
</span>
</span>
</div>
<div>
<span style="font-size: medium;"><span style="font-family: Calibri;" lang="EN-US"><span style="width: 3.34%;"> </span>
</span>
<span style="">(一)</span>
<span style="">不要有太多的条件分支。这个与处理器的流水</span>
<span style="">线技术有关。一条指令的执行一般会分成几个步骤,</span>
<span style="">比如取指、译指、执行指令等,很多处理器有</span>
<span style="font-family: Calibri;" lang="EN-US">7-20</span>
<span style="">个</span>
<span style="">左右的步骤,每条指令都需要顺序经过每个步骤。另</span>
<span style="">外指令是需要依次执行的。以三个步骤为例说明流水</span>
<span style="">线技术。每个步骤都需要特定的硬件模块执行,比如</span>
<span style="">取指需要取指模块完成,译指需要译指模块完成。假</span>
<span style="">设每个步骤耗时为</span>
<span style="font-family: Calibri;" lang="EN-US">t</span>
<span style="">,如果处理器只有执行结束一条指</span>
<span style="">令的所有步骤之后才执行下一条指令,那么三条指令</span>
<span style="">(</span>
<span style="font-family: Calibri;" lang="EN-US">A</span>
<span style="">、</span>
<span style="font-family: Calibri;" lang="EN-US">B</span>
<span style="">、</span>
<span style="font-family: Calibri;" lang="EN-US">C</span>
<span style="">)总共需要</span>
<span style="font-family: Calibri;" lang="EN-US">9t</span>
<span style="">时间。如果采用流水线技术</span>
<span style="">,那么当</span>
<span style="font-family: Calibri;" lang="EN-US">A</span>
<span style="">进入译指模块的时候,取指模块已经取出</span>
<span style="font-family: Calibri;" lang="EN-US">B</span>
</span>
<!-- [if !mso]>
<style>
v/:* {behavior:url(#default#VML);}
o/:* {behavior:url(#default#VML);}
p/:* {behavior:url(#default#VML);}
.shape {behavior:url(#default#VML);}
v/:textbox {display:none;}
</style>
<![endif]--><!-- [if !ppt]--><!-- [endif]-->
<div class="O">
<span style="font-size: medium;"><span style="">的指令了,当</span>
<span style="font-family: Calibri;" lang="EN-US">A</span>
<span style="">进入执行阶段的时候,</span>
<span style="font-family: Calibri;" lang="EN-US">B</span>
<span style="">进入译指阶段,</span>
<span style="font-family: Calibri;" lang="EN-US">C</span>
<span style="">进入取指阶段。这样下来三条指令只需花费</span>
<span style="font-family: Calibri;" lang="EN-US">5t</span>
<span style="">的时间,当指</span>
<span style="">令很多的时候,每条指令花费的时间应该是</span>
<span style="font-family: Calibri;" lang="EN-US">t</span>
<span style="">。当然这个是理想情况,导致流水线中断的有多个原因,比如数据依赖</span>
<span style="">和条件分支,这里说一下条件分支。在条件分支下,</span>
<span style="font-family: Calibri;" lang="EN-US">A</span>
<span style="">的下一条指令可能不是</span>
<span style="font-family: Calibri;" lang="EN-US">B</span>
<span style="">而是</span>
<span style="font-family: Calibri;" lang="EN-US">E</span>
<span style="">。如果</span>
<span style="font-family: Calibri;" lang="EN-US">A</span>
<span style="">执行完成之后,发现</span>
<span style="">下一条指令是</span>
<span style="font-family: Calibri;" lang="EN-US">E</span>
<span style="">而不是</span>
<span style="font-family: Calibri;" lang="EN-US">B</span>
<span style="">,这个时候,</span>
<span style="font-family: Calibri;" lang="EN-US">B</span>
<span style="">已经完成了译指,</span>
<span style="font-family: Calibri;" lang="EN-US">C</span>
<span style="">完成了取指。但是不但白做了,还增加了额外的负担:</span>
<span style="">清空流水线,这个对效率的影响是很明显的。因此对于那些对效率要求很高的算</span>
</span>
<!-- [if !mso]>
<style>
v/:* {behavior:url(#default#VML);}
o/:* {behavior:url(#default#VML);}
p/:* {behavior:url(#default#VML);}
.shape {behavior:url(#default#VML);}
v/:textbox {display:none;}
</style>
<![endif]--><!-- [if !ppt]--><!-- [endif]-->
<div class="O">
<span style="font-size: medium;">
</span>
<div>
<span style="font-size: medium;"><span style="">法而言最好减少条件分支。</span>
<span style="font-family: Calibri;" lang="EN-US">Gcc</span>
<span style="">提供了一些属性,用于</span>
<span style="">在</span>
<span style="font-family: Calibri;" lang="EN-US">if</span>
<span style="">语句中判断这个</span>
<span style="font-family: Calibri;" lang="EN-US">if</span>
<span style="">是有可能还是不大可能。比如内</span>
<span style="">存分配失败不大可能出现,可以写成</span>
<span style="font-family: Calibri;" lang="EN-US">if (unlikely(NULL </span>
<span style="font-family: Calibri;" lang="EN-US">== p))</span>
<span style="">表示</span>
<span style="font-family: Calibri;" lang="EN-US">p==NULL</span>
<span style="">出现的概率很小,那么编译器就</span>
<span style="">会优化这段代码,让流水线的下一条指令是</span>
<span style="font-family: Calibri;" lang="EN-US">if</span>
<span style="">外面的代</span>
<span style="">码。对于那些可能性很大的代码,则写成</span>
<span style="font-family: Calibri;" lang="EN-US">if </span>
<span style="font-family: Calibri;" lang="EN-US">(likely(NULL != p))</span>
<span style="">则流水线的下一条指令是</span>
<span style="font-family: Calibri;" lang="EN-US">if</span>
<span style="">内部的代</span>
<span style="">码</span>
<span style="">。</span>
</span>
</div>
<div>
<!-- [if !mso]>
<style>
v/:* {behavior:url(#default#VML);}
o/:* {behavior:url(#default#VML);}
p/:* {behavior:url(#default#VML);}
.shape {behavior:url(#default#VML);}
v/:textbox {display:none;}
</style>
<![endif]--><!-- [if !ppt]--><!-- [endif]-->
<div class="O">
<div>
<span style="font-size: medium;"><span style="">(二)</span>
<span style="">如果内存不成问题或者有其他原因,尽可能用等</span>
<span style="">同于处理器位宽的类型。这个对于</span>
<span style="font-family: Calibri;" lang="EN-US">mips</span>
<span style="">的</span>
<span style="font-family: Calibri;" lang="EN-US">CPU</span>
<span style="">来说尤</span>
<span style="">为关键,一来影响访存,而来影响运算。从</span>
<span style="font-family: Calibri;" lang="EN-US">PPC</span>
<span style="">的反</span>
<span style="">汇编来看,如果是两个</span>
<span style="font-family: Calibri;" lang="EN-US">ushort_t</span>
<span style="">进行逻辑运算也需要扩</span>
<span style="">充成</span>
<span style="font-family: Calibri;" lang="EN-US">32</span>
<span style="">位的进行,扩充的过程是需要浪费时间的。
</span>
</span>
</div>
<div>
<span style="font-size: medium;"><span style="">(三)</span>
<span style="">能有</span>
<span style="font-family: Calibri;" lang="EN-US">++i</span>
<span style="">的地方最好别用</span>
<span style="font-family: Calibri;" lang="EN-US">i++</span>
<span style="">。当然这个大部分的</span>
<span style="">编译器可能会优化掉。</span>
<span style="font-family: Calibri;" lang="EN-US">i++</span>
<span style="">的过程比</span>
<span style="font-family: Calibri;" lang="EN-US">++i</span>
<span style="">要复杂多了,</span>
<span style="font-family: Calibri;" lang="EN-US">i++</span>
<span style="">,需要先备份一下</span>
<span style="font-family: Calibri;" lang="EN-US">i</span>
<span style="">,然后加</span>
<span style="font-family: Calibri;" lang="EN-US">1</span>
<span style="">,再执行相应的操作</span>
<span style="">。</span>
</span>
</div>
</div>
</div>
<span style="font-size: medium;">
</span>

</div>
</div>
</div>
</div>
</div>
<span style="font-size: medium;">
</span>
</div>
</div>
<span style="font-size: medium;">
</span>
</div>
</div>
<span style="font-size: medium;">
</span>

</div>
</div>
</div>
</div>
<span style="font-size: medium;">
</span>

</div>
</div>
<span style="font-size: medium;">
</span>

</div>
</div>
</div>
<span style="font-size: medium;">
</span>

</div>
</div>
<span style="font-size: medium;">
</span>
</div>
</div>
<span style="font-size: medium;">
</span>
</div>
</div>
<span style="font-size: medium;">
</span>
</div>
</div>
<span style="font-size: medium;">
</span>
</div>
<span style="font-size: medium;">
</span>

</div>
</div>
<span style="font-size: medium;">
</span>

</div>
</div>
<span style="font-size: medium;">
</span>
</div>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值