研究不定数量参数的函数并实现一个printf函数

1、前提知识html

一、如何传递参数(主函数)编程

a、函数的参数是经过栈传递,并且是从右到左依次入栈ide

b、即便是char型变量,在传递参数时,也是占用两个字节,由于push操做是两个字节为单位的。 函数

c、showchar('a',2)这样的传入两个常数,也会在堆栈中开辟两个空间,也即对应两个实参变量。post

二、函数如何接收参数(子函数)测试

a、 函数接受形参是经过从栈中取的this

b、经过BP能够找到传入参数的值,BP+4是第一个参数,BP+6是第二个参数......取参数是从左到右取的 url

三、如何释放参数(主函数)spa

   释放参数能够经过屡次pop来实现。有时是经过“add sp,+数值”来实现的。3d

2、研究一个简单的不定数量参数的函数

  测试代码 

void showchar(int,char,...);

main()
{
    showchar(8,2,'a','b','c','d','e','f','g','h');
}

void showchar(int n,char color,...)
{
    int i;
    char r;
    for (i = 0; i!=n; i++)
    {
        r = *(char *)(_BP+8+i+i);
        r = color;
    }
}
View Code

 一、main函数  

main()
{
    showchar(8,2,'a','b','c','d','e','f','g','h');
}

对应的反汇编代码

二、showchar函数 

void showchar(int n,char color,...)
{
    int i;
    char r;
    for (i = 0; i!=n; i++)
    {
        r = *(char *)(_BP+8+i+i);
        r = color;
    }
}

   对应的反汇编代码

三、分析

  函数经过参数一来控制显示字符的循环次数,经过这种方式来接收多个参数。

3、printf函数肯定不定参数个数的方法

  经过第一个参数所指向的字符串中%个数来肯定不定参数的个数。

4、实现一个printf函数

一、包含printf函数、测试函数的C程序 

extern void showenter(void);                 /* 在模块showchar.obj中定义 */
extern void showchar(char);                    /* 在模块showchar.obj中定义 */
                                            /* 在光标位置显示字符,同时光标后移 */
static void printf(const char * str,...);   /* 使用本身定义的printf函数  */
static void showint(int num);                

main()
{
    printf("\nhello %c%c%cld!\n",'w','o','r');
    printf("\n%c %d %c %d\n",'l',6553,'o',123);
}

/***************************************************************************
函数功能:支持%c、%d功能的printf函数
输入参数:str以及不定参数
前提知识:不管char型,仍是int型,在传递参数时,都是入栈操做,并且都是以两个
          字节入栈的。由于push指令只能以两个字节来操做。
实现思路:经过%来统计获取不定参数的个数,参数从堆栈中去获取           
****************************************************************************/
static void printf(const char * str,...)
{
    char strnum = 0;                                        /* 记录读出字符串str的位置 */
    char paraaddr = 0;                                        /* 记录读出不定参数的位置 */
    
    while(str[strnum]){                                        /* 取出字符为NULL,结束 */
        if(str[strnum] == '%'){                                /* 取出字符为%,看下一个字符 */
            strnum++;                                        /* 读取字符串的位置后移 */
            switch(str[strnum]){                            /* 根据%后边字符的值,选择不一样的操做 */
                case 'c':                                    
                         showchar(*(char*)(_BP+6+paraaddr));/* 为c,则将一个char型大小的参数取出显示 */
                         paraaddr += 2;                        /* 读取不定参数的位置后移 */
                         break;
                case 'd':
                        showint(*(int*)(_BP+6+paraaddr));    /* 为d,则将一个int型大小的参数取出显示 */
                        paraaddr += 2;                        /* 读取不定参数的位置后移 */
                        break;
                default:
                        showchar('%');                        /* 不是d,也不是c,就将以前的%显示 */
                        showchar(str[strnum]);                /* 还要把当前字符显示 */
            }
        }
        else                                                /* 取出字符非%,直接显示 */
        {
            if(str[strnum] == '\n')                            /* 换行符 */
            {
                showenter();                                /* 用函数showenter显示 */
            }
            else{
                showchar(str[strnum]);                        /* 其余状况,直接显示 */
            }            
        }
        strnum++;                                            /* 读取字符串的位置后移  */
    }
}
/***************************************************************************
函数功能:显示整型数字
输入参数:num
实现思路:先将整型数字从个位依次向高位取数,存在堆栈中。显示的时候,从堆栈的
          高位第一个非零数字开始显示。
存在问题:函数在VC6.0上能正确运行,可是在TC2.0上不能,好比说不能显示65535
猜想缘由:VC6.0和TC2.0对整型的定义是不一样的,前者是4个byte的存储空间,然后者只
          有两个
****************************************************************************/
static void showint(int num)
{
    char bufstk[5];                        /* 定义栈空间 */
    char p;                                /* 栈顶 */
    
    for(p = 0; p < 5; p++){
        bufstk[p] = num % 10;            /* 从低位到高位依次入栈 */
        num /= 10;
    }
    
    while((p > 0)&&(bufstk[--p] == 0)); /* 舍去高位为0的数字,但不舍弃num=0的个位0 */
    
    do{
        showchar(bufstk[p]+'0');        /* 显示有效数字 */
    }
    while(p--);                            /* 直到栈空 */
}
View Code

 二、包含在光标位置显示一个字符和显示换行的汇编程序

 PUBLIC _SHOWCHAR
 PUBLIC _SHOWENTER
_TEXT SEGMENT BYTE PUBLIC 'CODE'
  ASSUME CS: _TEXT
;==================================================================
;函数名称:showchar
;函数功能:显示一个字符
;输入参数:在堆栈中,具体说来是(返回地址+2),目的是为了和C程序无缝对接
;==================================================================  
_SHOWCHAR  PROC NEAR

    push ax            ;用到的中间寄存器入栈保存
    push cx
    push bx
    push bp
    
    mov bp,sp        ;模拟C程序的反汇编程序
    mov ah,0eh        ;调用"int 10h"的第0e号功能,显示字符且光标后移
    mov al,[bp+10]    ;字符
    mov bl,07h        ;颜色为黑底白字
    mov bh,0        ;第0页
    mov cx,1        ;重复1次
    int 10h
    
    pop bp
    pop bx
    pop cx
    pop ax
    ret

_SHOWCHAR  ENDP

;==================================================================
;函数名称:showenter
;函数功能:显示'\n'
;输入参数:无
;==================================================================
_SHOWENTER  PROC NEAR

    push bx
    push ax
    push dx
    
    
    mov bh,0    ;页号为0
    mov ah,3     ;取当前光标位置
    int 10h     ;返回参数。DH=行号,DL=列号
    
    inc dh         ;行号加1
    mov dl,0    ;列号为0
    mov ah,2     ;置光标位置
    int 10h     ;入口参数。DH=行号,DL=列号
    
    pop dx
    pop ax
    pop bx
    ret

_SHOWENTER  ENDP
_TEXT  ENDS
   END
View Code

三、编译方法

 
   《汇编语言》326页 研究实验5 “函数如何接收不定数量的参数”
相关文章
相关标签/搜索