研究不定數量參數的函數並實現一個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 「函數如何接收不定數量的參數」
相關文章
相關標籤/搜索