q=(++j)+(++j)+(++j)_变量自增问题

来源:互联网 发布:数据存储 概念 编辑:程序博客网 时间:2024/05/15 07:39

自增1,自减1运算符:

               自增 1 运算符记为“++”,其功能是使变量的值自增 1。 

               自减1运算符记为“--”,其功能是使变量值自减1。

自增1,自减1运算

               ++i      i自增1后再参与其他运算

               --i        i自减1后再参与其他运算

               i++      i参与运算后,i的值再自增1

               i--        i参与运算后,i的值再自减1

以下有一个例子:

               int i=5;
               int j=5;
               int q;

               q=(++j)+(++j)+(++j);

分别在VC 6.0 与VS 2010编译器中运行之后我们会得到不同的结果

              VC 6.0中运行得到q=22

              VS 2010中运行得到q=24

这是为什么?????????????????????????????????????

我们看一下底层运行机制

VC 6.0:

 1 6:    q=(++j)+(++j)+(++j);

 2 00401036   mov        eax,dword ptr [ebp-8]           移动J=5到寄存器eax

 3 00401039   add        eax,1                                       在寄存器eax值上加1,eax=6

 4 0040103C  mov         dword ptr [ebp-8],eax         把寄存器的值移动到变量j上去,j=6

 5 0040103F  mov         ecx,dword ptr [ebp-8]           移动J=6到寄存器ecx

 6 00401042   add        ecx,1                                       在寄存器上ecx+1,j=6

 7 00401045   mov        dword ptr [ebp-8],ecx          把寄存器ecx上的值移到J上去,J=7

 8 00401048   mov        edx,dword ptr [ebp-8]         把J=7移动到寄存器edx=7

 9 0040104B  add         edx,dword ptr [ebp-8]         edx值+j 此时j=7,edx=7+7

100040104E   mov         eax,dword ptr [ebp-8]          把j=7Move给 第一个寄存器eax

11 00401051  add         eax,1                                       eax再加1,此时寄存器eax=8

12 00401054  mov         dword ptr [ebp-8],eax         把此时的eax的值move给 j=8

13 00401057  add         edx,dword ptr [ebp-8]          edx值= edx+j =14+8

140040105A   mov         dword ptr [ebp-0Ch],edx      edx值move给 j =22

VS 2010:

1  q =(++j)+(++j)+(++j);

 2 003A1815 mov        eax,dword ptr [j]   //eax = 5,j =5

 3 003A1818  add         eax,1   //eax = 6

 4 003A181B mov        dword ptr [j],eax  j = 6

 5 003A181E mov        ecx,dword ptr [j]  ecx = 6

 6 003A1821  add         ecx,1  ecx = 7

 7 003A1824 mov        dword ptr [j],ecx  j = 7

 8 003A1827 mov        edx,dword ptr [j]   edx = 7

 9 003A182A  add         edx,1   edx = 8

10 003A182D mov         dword ptr [j],edx   j = 8

11 003A1830 mov         eax,dword ptr [j] eax = 8

12 003A1833 add         eax,dword ptr [j] eax = 16

13 003A1836 add         eax,dword ptr [j]  eax = 24

14003A1839  mov         dword ptr [q],eax

接下来我们队计算机组成原理中一些知识进行了解:

             寄存器简介(转)

           4个数据寄存器(EAXEBXECXEDX)
         2
个变址和指针寄存器(ESIEDI)
         2个指针寄存器(ESPEBP)

      那么如何理解eax,ax,al(ah)之间的关系呢?
      专业点可以这样解释:Eax32位寄存器,ax16位寄存器,al(ah)是八位寄存器。
      那么eax存储的数据就是ax的两倍,axal(ah)的两倍。

       Eax可以存储的数字是DWORD(双字)ax存储的是WORD(字)AL(AH)存储的是BYTE(字节),那么为什么又有AHAL呢,我们可以这样理解

      AX=AH+ALAH存储的是AX的高8位数据,AL存储的是AX的低八位数据。H这里就是HIGH,L就是LOW.

      假设eax是红色区域,那么eax现在就是64636261那么ax就是eax的低十六位,也就是6261Al61AH62



       其他ebx,ecx,edx也有类似的bx,bl,bh等对应的寄存器,原理和上面相同。

在用途方面,他们有各自默认的用途:
Eax用来保存所有API函数的返回值。
寄存器AX和AL通常称为累加器(Accumulator),用累加器进行的操作可能需要更少时间。累加器可用于乘、除、输入/输出等操作,它们的使用频率很高;
寄存器BX称为基地址寄存器(BaseRegister)。它可作为存储器指针来使用;
寄存器CX称为计数寄存器(Count Register)。在循环和字符串操作时,要用它来控制循环次数;在位操作中,当移多位时,要用CL来指明移位的位数;
寄存器DX称为数据寄存器(DataRegister)。在进行乘、除运算时,它可作为默认的操作数参与运算,也可用于存放I/O的端口地址。

由于存储的数据大小关系,AX、BX、CX和DX不能作为基址和变址寄存器来存放存储单元的地址, 32位寄存器EAX、EBX、ECX和EDX不仅可传送数据、暂存数据保存算术逻辑运算结果,而且也可作为指针寄存器,所以,这些32位寄存器更具有通用性。(什么是基址,什么是变址以后会说到)

2个变址和指针寄存器(ESI和EDI)
32位CPU有2个32位通用寄存器ESI和EDI。其低16位对应先前CPU中的SI和DI,对低16位数据的存取,不影响高16位的数据。

寄存器ESI、EDI、SI和DI称为变址寄存器(Index Register),它们主要用于存放存储单元在段内的偏移量,用它们可实现多种存储器操作数的寻址方式,为以不同的地址形式访问存储单元提供方便。
变址寄存器不可分割成8位寄存器。作为通用寄存器,也可存储算术逻辑运算的操作数和运算结果。它们可作一般的存储器指针使用。在字符串操作指令的执行过程中,对它们有特定的要求,而且还具有特殊的功能。

2个重要的指针寄存器(ESP和EBP)


这两个指针寄存器都和“栈”这个神秘的东东有关,那么什么是栈呢?这俩指针寄存器又有何作用呢?


从计算机科学的角度看,栈是一种数据结构,是一种先进后出的数据表。栈的最常见操作有两种:Push(入栈)和Pop(出栈)。


我们可以把栈想象成一摞扑克牌:
PUSH:为栈增加一个元素的操作是push,相当于在这摞扑克牌最上面再放一张

POP:从栈中取出一个元素的操作叫做POP,相当于从这摞扑克牌取出最上面的一

张。

TOP:标识栈顶位置,并且是动态变化的。每做一次PUSH 操作,它都会自增1;

相反,每做一次POP 操作,它会自减1。栈顶元素相当于扑克牌最上面一张,只有


这张牌的花色是当前可以看到的。

BASE:标识栈底位置,它记录着扑克牌最下面一张的位置。BASE 用于防止栈空后

继续弹栈(牌发完时就不能再去揭牌了)。很明显,一般情况下,BASE 是不会变动


的。

用王爽《汇编语言》中的图说明一下push和pop操作
代码如下:
mov ax,0123H
push ax
mov bx,2266H
push bx
mov cx,1122H
pop ax
pop bx
pop cx

mov是传送数据的指令,mov ax,0123H表明把0123H这个值给ax
H代表0123是十六进制数



mov是传送数据的指令,mov ax,0123H表明把0123H这个值给ax
H代表0123是十六进制数
图中左边的10000H等数值表明内存地址
箭头指向栈顶位置

那么针对此例栈底就是1000FH
栈顶由于入栈和出栈操作在不断变化。

那么在这里栈底1000FH就是BP 栈顶(不断变化的箭头)就是SP
(BP和SP分别是16位下的寄存器,与ebp,esp类似)

内存的栈区实际上指的就是系统栈。系统栈由系统自动维护,它用于实现高级语言中函

数的调用。对于类似C 语言这样的高级语言,我们无需担心他们是如何操作的。一般说来,只有在使用汇编语言的时候,才需要和它直接打交道。

那么ESP和EBP指的分别是什么呢?

(1)ESP:栈指针寄存器(extendedstack pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的栈顶。
(2)EBP:基址指针寄存器(extended base pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的底部。