王爽老师 汇编语言 研究试验5 函数如何接收不定数量的参数

时间:2022-01-27 01:25:27

     研究试验5   函数如何接收不定数量的参数

一、按照书上的步骤进行试验。

1.写一个程序a.c:

 

①.MOV AX,0002

PUSH AX                  传递int型数据2,将2入栈

②.MOV AL,61

PUSH AX                  传递char型数据‘a’,并将其入栈

③.CALL 020B                调用showchar函数

④.020E:MOV AL,[BP+04]     取‘a’数据

⑤.MOV BX,B800

MOV ES,BX

MOV BX,0690

ES:

MOV [BX],AL              把a放到显存中

⑥.MOV AL,[BP+06]           从栈中取出2

⑦.MOV BX,B800

MOV ES,BX

MOV BX,0691

ES:

MOV [BX],AL              将2放到显存中

⑧.POP BP

RET                       程序返回到调用showchar函数的下一条指令

⑨.POP CX

POP CX                   将‘a’和2弹出

⑩.POP BP

RET                       结束

2.写一个程序b.c:

①.MOV AX,0068

    PUSH AX

    MOV AX,0067

    PUSH AX

    MOV AX,0066

    PUSH AX

    MOV AX,0065

    PUSH AX

    MOV AX,0064

    PUSH AX

    MOV AX,0063

    PUSH AX

    MOV AX,0062

    PUSH AX

    MOV AX,0061

    PUSH AX

    MOV AX,0002

    PUSH AX

    MOV AX,0008

    PUSH AX                   将showchar的参数入栈

②. PUSH SI

     XOR SI,SI

     JMP 027E

027E:CMP SI,[BP+04]

     JNZ 0235                

 si相当于一个计数器,与[BP+04]比较,也就是与8比较,不相等则转0235。

③.MOV BX,BP

ADD BX,SI

ADD BX,SI

ADD BX,+08  

MOV AL,[BX]

PUSH AX              

[bp+si+si+8]找到最后一个入栈的数据,放到ax中。

④.MOV AX,SI

CWD

PUSH DX

PUSH  AX

MOV AX,SI

CWD

POP BX

POP CX

ADD BX,AX

ADC CX,DX

ADD BX,0690

ADC CX,B800

MOV ES,CX 

这里es是显存段地址,bx是相应的偏移地址。

CWD是汇编语言中的字扩展指令,它的功能是将一个字型变量扩展为双字型变量。高位在DX,低位在AX。

⑤.POP AX

   ES:

   MOV [BX],AL

   将‘a’放到显存上

⑥.MOV AL,[BP+06]

   PUSH AX

    MOV AX,SI

CWD

PUSH DX

PUSH  AX

MOV AX,SI

CWD

POP BX

POP CX

ADD BX,AX

ADC CX,DX

ADD BX,0691

ADC CX,B800

MOV ES,CX

   POP AX

   ES:

MOV [BX],AL

INC SI

将颜色放入显存的高位,显示一个绿色的字符‘a’,将计数器加1。

接下来SI与8比较,小于8转到0235执行,依次将‘a’到‘h’显示。 

3.编写一个c.c函数来研究printf函数。

 

 分析上面的汇编代码,得出:依次将2,1,‘b’,‘a’入栈。调用printf函数显示。

 然后又将194入栈,不知道为什么,查看194处的代码。

  可以看到194处存放的是printf函数中第一个字符串中存放的数据,而且都是以%开头,0为结尾。猜想是printf是用%来确定参数的,以0来结尾。下面来验证:

将196处改为0,如果猜想正确,那么就应该输出一个字符‘a’。

 研究证明:猜想正确。

4.实现一个简单的printf函数,只需要支持“%c,%d”即可。

 

程序中:

char buffer[10];         存放转换为ASCII码的数字字符

int a=0;             存放通过参数传递来的int型数据

int b=0;             存放int型数据位数

int m=0;             屏幕显示字符位置

int n=0;             参数位置

 

二、解决的问题。

1.通过分析a.c的汇编代码,得出:

 ⑴.main函数是如何给showchar传递参数的?

    用push ax,将main函数的参数压入栈中。

 ⑵.showchar是如何接收参数的?

 用bp寄存器对栈中数据进行操作,[bp+04][bp+06]将‘a’和2取出  

2.通过分析b.c的汇编代码,得出:

 showchar函数是如何知道要显示多少个字符的?

 由程序可看出,字符的数量是由第一个参数传入的。

3.printf函数是如何知道有多少个参数的?

  printf是用%来确定参数的,以0来结尾。

三、未解决的问题。

1.为什么函数声明后要加分号(;),而子函数不用加分号呢?

  如a.c:第一行void showchar(char a,int b);

        第四行void showchar(char a,int b)

2.程序b.c中最后为什么sp要加14h。

3.a.c中为什么‘a’和2存在了[bp+4]和[bp+6]?栈中先是保存了bp,那[bp+2]的地方放的是什么?

四、研究体会

    通过这个试验的学习,我明白了printf函数是如何确定参数个数的,如何传递参数并显示的,理解了这些,printf函数的编写就相对容易些了。